Skip to content

Commit

Permalink
use Authorization: Bearer instead of idToken header
Browse files Browse the repository at this point in the history
  • Loading branch information
SanderGi committed Apr 5, 2024
1 parent a5e547d commit ba415e3
Show file tree
Hide file tree
Showing 11 changed files with 56 additions and 46 deletions.
4 changes: 2 additions & 2 deletions .badges/coverage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions .badges/file-count.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions .badges/lines-of-code.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion nodemon.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"ignore": [".git", "node_modules/**/node_modules", "server/super_admin/**"],
"watch": ["server/**", "public/**", "server/schema.sql"]
"watch": ["server/**", "server/schema.sql"]
}
2 changes: 1 addition & 1 deletion public/util/Auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export async function login() {
console.log('Logging in...');
if (auth.currentUser) {
// use firebase auth information if available (otherwise we rely on the existing idtoken session storage item if it has been set)
let idToken = await auth.currentUser.getIdToken(/* forceRefresh */ true);
const idToken = await auth.currentUser.getIdToken(/* forceRefresh */ true);
sessionStorage.setItem('idtoken', idToken);
} else if (!sessionStorage.getItem('idtoken')) return false;
const res = await GET('/isLoggedIn');
Expand Down
10 changes: 5 additions & 5 deletions public/util/Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const IS_SAFARI = /^((?!chrome|android).)*safari/i.test(navigator.userAge
/** Requests a resource from the server. Should only retrieve data */
export async function GET(url) {
return await fetch(SERVER_URL + url, {
headers: { idtoken: sessionStorage.getItem('idtoken') },
headers: { Authorization: 'Bearer ' + sessionStorage.getItem('idtoken') },
});
}

Expand All @@ -20,7 +20,7 @@ export async function POST(url, data) {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
idtoken: sessionStorage.getItem('idtoken'),
Authorization: 'Bearer ' + sessionStorage.getItem('idtoken'),
},
body: JSON.stringify(data),
});
Expand All @@ -33,7 +33,7 @@ export async function PATCH(url, data) {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
idtoken: sessionStorage.getItem('idtoken'),
Authorization: 'Bearer ' + sessionStorage.getItem('idtoken'),
},
body: JSON.stringify(data),
});
Expand All @@ -43,7 +43,7 @@ export async function PATCH(url, data) {
export async function DELETE(url) {
return await fetch(SERVER_URL + url, {
method: 'DELETE',
headers: { idtoken: sessionStorage.getItem('idtoken') },
headers: { Authorization: 'Bearer ' + sessionStorage.getItem('idtoken') },
});
}

Expand All @@ -54,7 +54,7 @@ export async function PUT(url, data) {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
idtoken: sessionStorage.getItem('idtoken'),
Authorization: 'Bearer ' + sessionStorage.getItem('idtoken'),
},
body: JSON.stringify(data),
});
Expand Down
6 changes: 4 additions & 2 deletions scripts/badges.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const fs = require('fs');
const exec = require('child_process').exec;

if (!fs.existsSync('./.badges')) fs.mkdirSync('./.badges');

function createBadge(label, value, leftWidth, rightWidth, color, filename) {
const totalWidth = leftWidth + rightWidth;
const svg = /*html*/ `
Expand All @@ -18,10 +20,10 @@ function createBadge(label, value, leftWidth, rightWidth, color, filename) {
}" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)">${label}</text>
<text x="${5 * leftWidth}" y="140" transform="scale(.1)" fill="#fff">${label}</text>
<text aria-hidden="true" x="${
8 * leftWidth + 8 * rightWidth
10 * leftWidth + value.toString().length + 5 * rightWidth
}" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)">${value}</text>
<text x="${
8 * leftWidth + 8 * rightWidth
10 * leftWidth + value.toString().length + 5 * rightWidth
}" y="140" transform="scale(.1)" fill="#fff">${value}</text>
</g>
</svg>
Expand Down
4 changes: 2 additions & 2 deletions server/Auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,11 @@ async function getAccess(uid, businessId, requiredPrivileges = {}) {
* @effects sends response status error codes for failed auth
*/
async function handleAuth(request, response, businessId = false, requiredPrivileges = {}) {
if (!request.headers.idtoken) {
if (!request.headers.authorization || !request.headers.authorization.startsWith('Bearer ')) {
response.status(400).send('No idtoken provided, user does not appear to be signed in');
return false;
}
const uid = await getUID(request.headers.idtoken);
const uid = await getUID(request.headers.authorization.substring(7));
if (!uid) {
response.status(401).send('Idtoken is invalid, login has likely expired');
return false;
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion test/client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const assert = require('node:assert');
// eslint-disable-next-line no-unused-vars
const { Builder, Browser, By, Key, until, WebDriver } = require('selenium-webdriver'); // read about selenium here: https://www.selenium.dev/documentation/en/webdriver/
const chrome = require('selenium-webdriver/chrome'); // read about chrome options here: https://chromedriver.chromium.org/capabilities
const { captureConsole } = require('./utils.js');
const { captureConsole } = require('./captureConsole.js');
captureConsole('./test.client.log');

describe('Client', () => {
Expand Down
60 changes: 34 additions & 26 deletions test/server.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const { describe, it, before, beforeEach } = require('node:test'); // read about
const assert = require('node:assert');
const request = require('supertest'); // we use supertest to test HTTP requests/responses. Read more here: https://github.com/ladjs/supertest
const { v4 } = require('uuid');
const { captureConsole } = require('./utils.js');
const { captureConsole } = require('./captureConsole.js');
captureConsole('./test.server.log');

// import code to test
Expand Down Expand Up @@ -145,16 +145,24 @@ describe('Server', () => {
request(app).get('/isLoggedIn').expect(400).end(done);
});
it('Should return 401 Unauthorized when an invalid token is provided', (t, done) => {
request(app).get('/isLoggedIn').set('idtoken', INVALID_TOKEN).expect(401).end(done);
request(app)
.get('/isLoggedIn')
.set('Authorization', 'Bearer ' + INVALID_TOKEN)
.expect(401)
.end(done);
});
it('Should return 401 Unauthorized when a valid but expired token is provided', (t, done) => {
request(app).get('/isLoggedIn').set('idToken', EXPIRED_TOKEN).expect(401).end(done);
request(app)
.get('/isLoggedIn')
.set('Authorization', 'Bearer ' + EXPIRED_TOKEN)
.expect(401)
.end(done);
});
it('Should return 200 OK and the correct userid when a valid token is provided', (t, done) => {
mockToken(t);
request(app)
.get('/isLoggedIn')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.expect(200)
.expect('Content-Type', /text/)
.expect(VALID_AUTH.user_id)
Expand Down Expand Up @@ -274,14 +282,14 @@ describe('Server', () => {
]);
await request(app)
.get('/businesses/1/joincode')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.expect(403);
});
it('Should create a new user when handleAuth is called with a valid but unseen userid', async t => {
mockToken(t);
await request(app)
.get('/isLoggedIn')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.expect(200)
.expect('Content-Type', /text/)
.expect(VALID_AUTH.user_id);
Expand Down Expand Up @@ -388,7 +396,7 @@ describe('Server', () => {
mockToken(t);
await request(app)
.get('/businesses')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.expect(200)
.expect('Content-Type', /json/)
.expect([
Expand All @@ -412,7 +420,7 @@ describe('Server', () => {
mockToken(t);
await request(app)
.put('/businesses/' + businessId1 + '/name')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.query({ new: 'testname2' })
.expect(200);

Expand All @@ -431,7 +439,7 @@ describe('Server', () => {
mockToken(t);
await request(app)
.put('/businesses/' + businessId2 + '/name')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.query({ new: 'testname2' })
.expect(403);

Expand All @@ -444,7 +452,7 @@ describe('Server', () => {
mockToken(t);
await request(app)
.put('/businesses/' + businessId2 + '/name')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.query({ new: 'testname2' })
.expect(403);
});
Expand All @@ -461,14 +469,14 @@ describe('Server', () => {
skipTokenVerification(t, 'testuid', 'testname', 'testemail');
const res = await request(app)
.get('/businesses/' + businessId + '/joincode')
.set('idToken', 'testtoken')
.set('Authorization', 'Bearer testtoken')
.expect(200)
.expect('Content-Type', /json/);
mockToken(t);
const joincode = JSON.parse(res.text).joincode;
await request(app)
.post('/businesses/' + businessId + '/members')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.query({ joincode: joincode })
.expect(200);
const members = await db().all(
Expand All @@ -490,14 +498,14 @@ describe('Server', () => {
skipTokenVerification(t, 'testuid', 'testname', 'testemail');
const res = await request(app)
.get('/businesses/' + businessId1 + '/joincode')
.set('idToken', 'testtoken')
.set('Authorization', 'Bearer testtoken')
.expect(200)
.expect('Content-Type', /json/);
mockToken(t);
const joincode = JSON.parse(res.text).joincode;
await request(app)
.post('/businesses/' + businessId2 + '/members')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.query({ joincode: joincode })
.expect(403);
const members = await db().all(
Expand Down Expand Up @@ -533,11 +541,11 @@ describe('Server', () => {
mockToken(t, 2);
await request(app)
.delete('/businesses/' + businessId1 + '/members/me')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.expect(200);
await request(app)
.delete('/businesses/' + businessId2 + '/members/me')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.expect(403);
});
it('Should only allow kicking non-owner members', async t => {
Expand Down Expand Up @@ -567,17 +575,17 @@ describe('Server', () => {
// owner can't be removed
await request(app)
.delete('/businesses/' + businessId + '/members/' + VALID_AUTH.user_id)
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.expect(400);
// member can be removed
await request(app)
.delete('/businesses/' + businessId + '/members/testuid')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.expect(200);
// non-member can't be removed
await request(app)
.delete('/businesses/' + businessId + '/members/testuid')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.expect(400);
});
it('Should return the correct attendance data for a business', async t => {
Expand Down Expand Up @@ -616,7 +624,7 @@ describe('Server', () => {
mockToken(t, 1);
await request(app)
.get('/businesses/' + businessId + '/attendance')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.expect(200)
.expect('Content-Type', /json/)
.expect([
Expand Down Expand Up @@ -708,7 +716,7 @@ describe('Server', () => {
mockToken(t, 1);
await request(app)
.get('/businesses/' + businessId1)
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.query({ businessId: businessId1 })
.expect(200)
.expect('Content-Type', /json/)
Expand Down Expand Up @@ -751,19 +759,19 @@ describe('Server', () => {
// don't allow setting owner role
await request(app)
.put('/businesses/' + businessId + '/members/testuid/role')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.query({ new: 'owner' })
.expect(403);
// don't allow changing the owner's role
await request(app)
.put('/businesses/' + businessId + '/members/' + VALID_AUTH.user_id + '/role')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.query({ new: 'admin' })
.expect(403);
// allow setting other roles
await request(app)
.put('/businesses/' + businessId + '/members/testuid/role')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.query({ new: 'admin' })
.expect(200);
const members = await db().all(
Expand All @@ -777,12 +785,12 @@ describe('Server', () => {
mockToken(t, 2);
await request(app)
.put('/username')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.query({ new: 'testname' })
.expect(200);
await request(app)
.get('/username')
.set('idToken', VALID_TOKEN)
.set('Authorization', 'Bearer ' + VALID_TOKEN)
.expect(200)
.expect('Content-Type', /json/)
.expect({ name: 'testname' });
Expand Down

0 comments on commit ba415e3

Please sign in to comment.