mirror of
https://github.com/Piwigo/Piwigo.git
synced 2026-06-02 04:15:05 +02:00
fixes #2355 implement API key management system
- Added API key get, creation, editing, and revocation methods. - Updated the profile template to include API key management features. - Updated the database schema to support the new API key system, including additional fields for key management. - Added client-side JavaScript functionality to handle API key operations and display responses. - Update tools/htm.ws with the new way to authenticate. - Restriction of certain api methods when used with an api key - Backward compatibility with older apps
This commit is contained in:
+17
-2
@@ -84,6 +84,21 @@
|
||||
|
||||
|
||||
<form id="methodWrapper" style="display:none;">
|
||||
<div class="card">
|
||||
<h3 class="card-title"><i class="icon-cog-alt"></i>Authenticate with API Key (Header)</h3>
|
||||
<div class="card-content">
|
||||
<p class="header-description"> Introduced in Piwigo 16, you can now use an API key in the HTTP header
|
||||
to perform authenticated requests without a user session.
|
||||
For more details, check out our <a href="https://github.com/Piwigo/Piwigo/wiki/Piwigo-Web-API#api-key-authentication" target="_blank">documentation</a>.
|
||||
</p>
|
||||
<p class="header-warning">Doesn't work when you use "INVOKE (new window)"</p>
|
||||
<div class="header-setting">
|
||||
<p>Authorization:</p>
|
||||
<input type="text" id="apiKey" placeholder="pkid-xxxxxxxx-xxxxxxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" />
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- methodHeader -->
|
||||
|
||||
<div class="card" id="methodDescription" style="display:none;">
|
||||
<h3 class="card-title"><i class="icon-book"></i>Description</h3>
|
||||
<blockquote>
|
||||
@@ -134,7 +149,7 @@
|
||||
<div class="select">
|
||||
<select id="responseFormat">
|
||||
<option value="json" selected>JSON</option>
|
||||
<option value="rest" selected>REST (xml)</option>
|
||||
<option value="rest">REST (xml)</option>
|
||||
<option value="php">PHP serial</option>
|
||||
<option value="xmlrpc">XML RPC</option>
|
||||
</select>
|
||||
@@ -187,7 +202,7 @@
|
||||
</div> <!-- the_container -->
|
||||
|
||||
<div id="the_footer">
|
||||
Copyright © 2002-2021 <a href="http://piwigo.org">Piwigo Team</a>
|
||||
Copyright © 2002-2025 <a href="http://piwigo.org">Piwigo Team</a>
|
||||
</div> <!-- the_footer -->
|
||||
</div>
|
||||
|
||||
|
||||
@@ -349,6 +349,29 @@ input[type="text"] {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header-setting {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.header-setting input {
|
||||
max-width: 580px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header-description {
|
||||
margin: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.header-warning {
|
||||
margin: 0;
|
||||
color: red;
|
||||
font-size: 12px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* #requestResultDisplay {
|
||||
background: white;
|
||||
} */
|
||||
|
||||
+75
-28
@@ -93,7 +93,8 @@ $(() => {
|
||||
url: ws_url,
|
||||
data: { format: "json", method: "reflection.getMethodList" }
|
||||
}).done(function (result) {
|
||||
console.log(result);
|
||||
// for debug
|
||||
//console.log(result);
|
||||
result = parsePwgJSON(result);
|
||||
|
||||
if (result != null) {
|
||||
@@ -328,6 +329,8 @@ $(() => {
|
||||
// invoke method
|
||||
function invokeMethod(methodName, newWindow) {
|
||||
|
||||
$('#json-viewer').jsonViewer({});
|
||||
|
||||
$('#requestURLDisplay').show();
|
||||
$('#requestResultDisplay').show();
|
||||
|
||||
@@ -335,6 +338,18 @@ $(() => {
|
||||
|
||||
let reqUrl = ws_url + "?format=" + $("#responseFormat").val();
|
||||
|
||||
const isJson = $("#responseFormat").val() === 'json';
|
||||
const authorization = $('#apiKey').val();
|
||||
const useCookie = '' === authorization;
|
||||
|
||||
let fetchOption = {};
|
||||
if (!useCookie) {
|
||||
fetchOption.credentials = 'omit';
|
||||
fetchOption.headers = {
|
||||
Authorization: authorization
|
||||
}
|
||||
}
|
||||
|
||||
// GET
|
||||
if ($("#requestFormat").val() == 'get') {
|
||||
reqUrl += "&method=" + methodName;
|
||||
@@ -361,19 +376,11 @@ $(() => {
|
||||
window.open(reqUrl);
|
||||
}
|
||||
else {
|
||||
if ($("#responseFormat").val() === 'json') {
|
||||
$("#invokeFrame").hide();
|
||||
$('#json-viewer').show();
|
||||
fetch(reqUrl)
|
||||
.then(data => data.json())
|
||||
.then(json => {
|
||||
$('#json-viewer').jsonViewer(json);
|
||||
})
|
||||
} else {
|
||||
$("#invokeFrame").show();
|
||||
$('#json-viewer').hide();
|
||||
$("#invokeFrame").attr('src', reqUrl);
|
||||
}
|
||||
fetch(reqUrl, fetchOption)
|
||||
.then(data => data.text())
|
||||
.then(data => {
|
||||
showResponseData(data);
|
||||
})
|
||||
}
|
||||
|
||||
$('#requestURLDisplay').find('.url').html(reqUrl).end()
|
||||
@@ -411,22 +418,30 @@ $(() => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!newWindow && $("#responseFormat").val() === 'json') {
|
||||
if (!newWindow) {
|
||||
$("#invokeFrame").hide();
|
||||
$('#json-viewer').show();
|
||||
jQuery.ajax({
|
||||
url: reqUrl,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
"method": methodName,
|
||||
...params
|
||||
},
|
||||
success : function(data) {
|
||||
$('#json-viewer').jsonViewer(data);
|
||||
}
|
||||
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('method', methodName);
|
||||
for (const key in params) {
|
||||
formData.append(key, params[key]);
|
||||
}
|
||||
|
||||
fetchOption.headers ??= {};
|
||||
fetchOption.headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
|
||||
fetch(reqUrl, {
|
||||
...fetchOption,
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(data => {
|
||||
return data.text();
|
||||
})
|
||||
.then(data => {
|
||||
showResponseData(data);
|
||||
});
|
||||
} else {
|
||||
$("#invokeFrame").show();
|
||||
$('#json-viewer').hide();
|
||||
@@ -490,4 +505,36 @@ $(() => {
|
||||
$('#the_body').addClass('dark-mode');
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function showResponseData(data) {
|
||||
const isJson = $("#responseFormat").val() === 'json';
|
||||
if (isJson) {
|
||||
try {
|
||||
const json = JSON.parse(data);
|
||||
$('#json-viewer').jsonViewer(json);
|
||||
$("#invokeFrame").hide();
|
||||
$('#json-viewer').show();
|
||||
} catch (error) {
|
||||
const iframe = $('#invokeFrame');
|
||||
const iframeDoc = iframe[0].contentDocument || iframe[0].contentWindow.document;
|
||||
|
||||
iframeDoc.open();
|
||||
iframeDoc.write(`<pre>${data}</pre>`);
|
||||
iframeDoc.close();
|
||||
$("#invokeFrame").show();
|
||||
$('#json-viewer').hide();
|
||||
}
|
||||
return;
|
||||
}
|
||||
const iframe = $('#invokeFrame');
|
||||
const iframeDoc = iframe[0].contentDocument || iframe[0].contentWindow.document;
|
||||
|
||||
iframeDoc.open();
|
||||
iframeDoc.write(data);
|
||||
iframeDoc.close();
|
||||
|
||||
$("#invokeFrame").show();
|
||||
$('#json-viewer').hide();
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user