diff --git a/.badges/coverage.svg b/.badges/coverage.svg index f3c5605..b7e5b4d 100644 --- a/.badges/coverage.svg +++ b/.badges/coverage.svg @@ -10,8 +10,8 @@ Coverage - - 76% + + 76% \ No newline at end of file diff --git a/.badges/file-count.svg b/.badges/file-count.svg index 54ad8d7..7b0eb48 100644 --- a/.badges/file-count.svg +++ b/.badges/file-count.svg @@ -1,6 +1,6 @@ - - Files: 63 + + Files: 66 @@ -10,8 +10,8 @@ Files - - 63 + + 66 \ No newline at end of file diff --git a/.badges/lines-of-code.svg b/.badges/lines-of-code.svg index 00e9870..0bf99b3 100644 --- a/.badges/lines-of-code.svg +++ b/.badges/lines-of-code.svg @@ -10,8 +10,8 @@ Lines of Code - - 6.4K + + 6.4K \ No newline at end of file diff --git a/nodemon.json b/nodemon.json index 61fb5c1..18201ef 100644 --- a/nodemon.json +++ b/nodemon.json @@ -1,4 +1,4 @@ { "ignore": [".git", "node_modules/**/node_modules", "server/super_admin/**"], - "watch": ["server/**", "public/**", "server/schema.sql"] + "watch": ["server/**", "server/schema.sql"] } diff --git a/public/util/Auth.js b/public/util/Auth.js index e64a27a..ac75fc5 100644 --- a/public/util/Auth.js +++ b/public/util/Auth.js @@ -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'); diff --git a/public/util/Client.js b/public/util/Client.js index 0bfc60b..734c0b6 100644 --- a/public/util/Client.js +++ b/public/util/Client.js @@ -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') }, }); } @@ -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), }); @@ -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), }); @@ -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') }, }); } @@ -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), }); diff --git a/scripts/badges.js b/scripts/badges.js index fa5b42b..3651105 100644 --- a/scripts/badges.js +++ b/scripts/badges.js @@ -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*/ ` @@ -18,10 +20,10 @@ function createBadge(label, value, leftWidth, rightWidth, color, filename) { }" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)">${label} ${label} ${value} diff --git a/server/Auth.js b/server/Auth.js index dc034ca..7784894 100644 --- a/server/Auth.js +++ b/server/Auth.js @@ -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; diff --git a/test/utils.js b/test/captureConsole.js similarity index 100% rename from test/utils.js rename to test/captureConsole.js diff --git a/test/client.test.js b/test/client.test.js index b8fddaf..b41bff6 100644 --- a/test/client.test.js +++ b/test/client.test.js @@ -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', () => { diff --git a/test/server.test.js b/test/server.test.js index 8f38547..05cc032 100644 --- a/test/server.test.js +++ b/test/server.test.js @@ -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 @@ -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) @@ -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); @@ -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([ @@ -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); @@ -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); @@ -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); }); @@ -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( @@ -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( @@ -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 => { @@ -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 => { @@ -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([ @@ -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/) @@ -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( @@ -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' });