Ensure CORS headers are always set on oauth endpoints

This commit is contained in:
Mia
2023-08-21 13:54:34 -05:00
parent cad185c424
commit 2b22a33bb3
3 changed files with 26 additions and 12 deletions

View File

@@ -520,7 +520,7 @@ export const actions: {[k: string]: QueryHandler} = {
// oauth/page - public-facing part
// oauth/api/page - api part (does the actual action)
async 'oauth/authorize'(params) {
this.setPrefix('');
this.allowCORS();
if (!params.redirect_uri) {
throw new ActionError("No redirect_uri provided");
}
@@ -543,7 +543,7 @@ export const actions: {[k: string]: QueryHandler} = {
// make a token if they don't already have it
async 'oauth/api/authorize'(params) {
this.setPrefix('');
this.allowCORS();
if (!this.user.loggedIn) {
throw new ActionError("You're not logged in.");
}
@@ -567,7 +567,7 @@ export const actions: {[k: string]: QueryHandler} = {
},
async 'oauth/api/refreshtoken'(params) {
this.setPrefix('');
this.allowCORS();
const clientInfo = await getOAuthClient(params.client_id);
const token = (params.token || "").toString();
if (!token) {
@@ -589,7 +589,7 @@ export const actions: {[k: string]: QueryHandler} = {
// validate assertion & get token if it's valid
async 'oauth/api/getassertion'(params) {
this.setPrefix('');
this.allowCORS();
const client = await getOAuthClient(params.client_id);
const token = (params.token || "").toString();
if (!token) {
@@ -606,7 +606,7 @@ export const actions: {[k: string]: QueryHandler} = {
},
'oauth/authorized'() {
this.setPrefix('');
this.allowCORS();
this.response.setHeader('Content-Type', 'text/html');
const content = OAUTH_AUTHORIZED_CONTENT;
this.response.setHeader('Content-Length', content.length);
@@ -620,7 +620,7 @@ export const actions: {[k: string]: QueryHandler} = {
const applications = [];
const tokens = await tables.oauthTokens.selectAll()`WHERE owner = ${this.user.id}`;
for (const token of tokens) {
const client = await tables.oauthClients.get(token.client, ['client_title']);
const client = await tables.oauthClients.get(token.client);
if (!client) throw new Error("Tokens exist for nonexistent application");
applications.push({title: client.client_title, url: client.origin_url});
}
@@ -637,11 +637,15 @@ export const actions: {[k: string]: QueryHandler} = {
if (!params.uri) {
throw new ActionError("Specify the URL of the application you wish to revoke access for.");
}
const tokenEntry = await tables.oauthTokens.selectOne()`WHERE origin_url = ${params.uri}`;
const client = await tables.oauthClients.selectOne()`WHERE origin_url = ${params.uri}`;
if (!client) {
throw new ActionError('No client found with that URL.');
}
const tokenEntry = await tables.oauthTokens.selectOne()`WHERE client = ${client.id}`;
if (!tokenEntry) {
throw new ActionError("That application doesn't have access granted to your account.");
}
await tables.oauthTokens.deleteOne()`WHERE origin_url = ${params.url}`;
await tables.oauthTokens.deleteAll()`WHERE client = ${client.id} and owner = ${this.user.id}`;
return {success: true};
},
};

View File

@@ -42,10 +42,11 @@
if (data.length < 1) return;
if (data[0] == ']') data = data.substr(1);
try {
return callback(JSON.parse(data));
data = (JSON.parse(data));
} catch {
return callback({data: data});
}
return callback(data);
};
};
function loadApplications() {
@@ -54,12 +55,16 @@
return alert(data.actionerror);
}
let buffer = `<strong>Applications authorized for account ${data.username}</strong>`;
if (!data.applications.length) {
buffer += ` None.`;
return $('#applications').html(buffer);
}
buffer += `<ul>`;
for (var [i, application] of data.applications.entries()) {
buffer += `<li>`;
buffer += `${application.title} (<a href="${application.url}">${application.url}</a>) `;
buffer += ` <button class="button greenbutton" id="revoke-${i}">Revoke access</button>`;
buf += `</li>`;
buffer += `</li>`;
}
$('#applications').html(buffer);
$('button').on('click', ev => {
@@ -74,6 +79,7 @@
});
}));
}
setTimeout(loadApplications, 10);
</script>
</body></html>

View File

@@ -177,6 +177,11 @@ export class ActionContext {
if (act) result.act = act;
return result;
}
allowCORS(origin?: string) {
if (!origin) origin = this.request.headers.origin || "*";
this.setHeader('Access-Control-Allow-Origin', origin);
this.setHeader('Access-Control-Allow-Credentials', 'true');
}
verifyCrossDomainRequest(): string {
if (typeof this.prefix === 'string') return this.prefix;
// No cross-domain multi-requests for security reasons.
@@ -197,8 +202,7 @@ export class ActionContext {
}
// Valid CORS request.
this.setHeader('Access-Control-Allow-Origin', origin);
this.setHeader('Access-Control-Allow-Credentials', 'true');
this.allowCORS(origin);
this.prefix = prefix;
return prefix;
}