Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix OpenAPI documentation login #1594

Merged
merged 3 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions src/api/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,14 @@ int check_client_auth(struct ftl_conn *api, const bool is_api)
return API_AUTH_EMPTYPASS;
}

// Does the client provide a session cookie?
// Does the client provide a session ID?
char sid[SID_SIZE];
const char *sid_source = "cookie";
const char *sid_source = "-";
// Try to extract SID from cookie
bool sid_avail = http_get_cookie_str(api, "sid", sid, SID_SIZE);
const bool cookie_auth = sid_avail;
bool sid_avail = false;

// If not, does the client provide a session ID via GET/POST?
if(!sid_avail && api->payload.avail)
if(api->payload.avail)
{
// Try to extract SID from form-encoded payload
if(GET_VAR("sid", sid, api->payload.raw) > 0)
Expand Down Expand Up @@ -166,6 +165,20 @@ int check_client_auth(struct ftl_conn *api, const bool is_api)
}
}

bool cookie_auth = false;
if(!sid_avail)
{
cookie_auth = http_get_cookie_str(api, "sid", sid, SID_SIZE);
if(cookie_auth)
{
// Mention source of SID
sid_source = "cookie";
// Mark SID as available
sid_avail = true;
}

}

if(!sid_avail)
{
log_debug(DEBUG_API, "API Authentication: FAIL (no SID provided)");
Expand Down
1 change: 0 additions & 1 deletion src/api/docs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ set(sources
hex/external/rapidoc-min.js.map
hex/external/highlight.min.js
hex/external/highlight-default.min.css
hex/external/geraintluff-sha256.min.js
hex/images/logo.svg
hex/specs/action.yaml
hex/specs/auth.yaml
Expand Down
1 change: 0 additions & 1 deletion src/api/docs/content/external/geraintluff-sha256.min.js

This file was deleted.

3 changes: 1 addition & 2 deletions src/api/docs/content/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
<!--<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,600&display=swap" rel="stylesheet">-->
<link rel="stylesheet" href="external/highlight-default.min.css">
<script src="external/highlight.min.js"></script>
<script src="external/geraintluff-sha256.min.js"></script>
<script type='text/javascript' src='external/rapidoc-min.js'></script>
<script type="text/javascript" src="pi-hole.js"></script>
<link href='index.css' rel='stylesheet'>
Expand Down Expand Up @@ -48,7 +47,7 @@
<div>Pi-hole API Documentation</div>
<div>
<input id='loginpw' type='password' size="4">
<button class='btn' id='loginbtn' onclick='login()'>Login</button>
<button class='btn' id='loginbtn' onclick='loginout()'>Login</button>
</div>
</div>
<!-- content at the bottom -->
Expand Down
73 changes: 25 additions & 48 deletions src/api/docs/content/pi-hole.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,40 @@
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */

function computeResponse(password, challenge) {
// Compute password hash twice to mitigate rainbow
// table vulnerability
console.log(password, challenge);
return sha256(challenge + ":" + sha256(sha256(password)));
}

// GET implementation
async function getData(url = '') {
const docEl = document.getElementById('thedoc');
const sid = docEl.attributes["api-key-value"].value;
const response = await fetch(url, {
method: 'GET',
headers: {'Content-Type': 'application/json'}
headers: {'Content-Type': 'application/json', 'X-FTL-SID': sid}
});
return response.json();
}

// DELETE implementation
async function deleteData(url = '') {
const docEl = document.getElementById('thedoc');
const sid = docEl.attributes["api-key-value"].value;
const response = await fetch(url, {
method: 'DELETE'
method: 'DELETE',
headers: {'X-FTL-SID': sid}
});
return response;
}

// POST implementation
async function postData(url = '', data = {}) {
const docEl = document.getElementById('thedoc');
const sid = docEl.attributes["api-key-value"].value;
const response = await fetch(url, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
headers: {'Content-Type': 'application/json', 'X-FTL-SID': sid},
body: JSON.stringify(data)
});
return response.json();
}

// Send response
function login2(response) {
postData('/api/auth', {response: response})
.then(data => {
if(data.session.valid === true) {
loginOk(data.session.sid);
} else {
loginFAIL();
}
})
.catch((error) => {
loginFAIL();
console.error('Error:', error);
});
}

// Mark login as OK
function loginOk(sid) {
const docEl = document.getElementById('thedoc');
Expand All @@ -78,37 +62,30 @@ function loginFAIL() {
// Mark logout as OK
function logoutOk() {
const docEl = document.getElementById('thedoc');
docEl.setAttribute('api-key-value', '-');
docEl.setAttribute('api-key-value', "-");
const btn = document.getElementById('loginbtn');
btn.classList.remove('green');
btn.classList.remove('red');
btn.textContent = 'Login';
}
function login1(pw)
{
getData('/api/auth')
.then(data => {
if("challenge" in data && data.challenge !== null) {
var response = computeResponse(pw, data.challenge);
login2(response);
} else if(data.session.valid === true) {
loginOk(data.session.sid);
} else {
loginFAIL();
}
})
.catch((error) => {
loginFAIL();
console.error('Error:', error);
});
}

// Start login sequence by getting challenge
function login(){
// Login using password
function loginout(){
const docEl = document.getElementById('thedoc');
if(docEl.attributes["api-key-value"].value === '-') {
var pw = document.getElementById('loginpw').value;
login1(pw);
postData('/api/auth', {password: pw})
.then(data => {
if(data.session.valid === true) {
loginOk(data.session.sid);
} else {
loginFAIL();
}
})
.catch((error) => {
loginFAIL();
console.error('Error:', error);
});
} else {
deleteData('/api/auth')
.then(logoutOk())
Expand Down
9 changes: 2 additions & 7 deletions src/api/docs/docs.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,14 @@ static const unsigned char rapidoc_min_js[] = {
#include "hex/external/rapidoc-min.js"
};

static const unsigned char rapidoc_min_map_js[] = {
static const unsigned char rapidoc_min_js_map[] = {
#include "hex/external/rapidoc-min.js.map"
};

static const unsigned char highlight_default_min_css[] = {
#include "hex/external/highlight-default.min.css"
};

static const unsigned char geraintluff_sha256_min_js[] = {
#include "hex/external/geraintluff-sha256.min.js"
};

static const unsigned char highlight_min_js[] = {
#include "hex/external/highlight.min.js"
};
Expand Down Expand Up @@ -139,10 +135,9 @@ struct {
{"index.css", "text/css", (const char*)index_css, sizeof(index_css)},
{"pi-hole.js", "application/javascript", (const char*)pi_hole_js, sizeof(pi_hole_js)},
{"external/rapidoc-min.js", "application/javascript", (const char*)rapidoc_min_js, sizeof(rapidoc_min_js)},
{"external/rapidoc-min.map.js", "text/plain", (const char*)rapidoc_min_map_js, sizeof(rapidoc_min_map_js)},
{"external/rapidoc-min.js.map", "text/plain", (const char*)rapidoc_min_js_map, sizeof(rapidoc_min_js_map)},
{"external/highlight-default.min.css", "text/css", (const char*)highlight_default_min_css, sizeof(highlight_default_min_css)},
{"external/highlight.min.js", "application/javascript", (const char*)highlight_min_js, sizeof(highlight_min_js)},
{"external/geraintluff-sha256.min.js", "application/javascript", (const char*)geraintluff_sha256_min_js, sizeof(geraintluff_sha256_min_js)},
{"images/logo.svg", "image/svg+xml", (const char*)images_logo_svg, sizeof(images_logo_svg)},
{"specs/auth.yaml", "text/plain", (const char*)specs_auth_yaml, sizeof(specs_auth_yaml)},
{"specs/clients.yaml", "text/plain", (const char*)specs_clients_yaml, sizeof(specs_clients_yaml)},
Expand Down