diff --git a/API Tests/BGApp/environments/BGApp.yml b/API Tests/BGApp/environments/BGApp.yml index 4865ed7..e51109b 100644 --- a/API Tests/BGApp/environments/BGApp.yml +++ b/API Tests/BGApp/environments/BGApp.yml @@ -1,3 +1,4 @@ +#file: noinspection SpellCheckingInspection name: BGApp variables: - name: BEARER_TOKEN diff --git a/API Tests/BGApp/opencollection.yml b/API Tests/BGApp/opencollection.yml index acfa2b7..dea3a3b 100644 --- a/API Tests/BGApp/opencollection.yml +++ b/API Tests/BGApp/opencollection.yml @@ -1,3 +1,4 @@ +#file: noinspection SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection,SpellCheckingInspection opencollection: 1.0.0 info: diff --git a/scripts/dbCreate.sql b/scripts/dbCreate.sql index ddac662..b7e0eea 100644 --- a/scripts/dbCreate.sql +++ b/scripts/dbCreate.sql @@ -1,3 +1,81 @@ +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + +-- noinspection SpellCheckingInspectionForFile + -- -- PostgreSQL database dump -- diff --git a/src/endpoints/auth.ts b/src/endpoints/auth.ts index be91267..43f8a37 100644 --- a/src/endpoints/auth.ts +++ b/src/endpoints/auth.ts @@ -20,7 +20,7 @@ async function login(request: UnwrappedRequest): Promise const tokenLifeSpanInDays = 30; const token = jwt.sign( { - u: verify.userId.raw, + u: verify.userId, r: verify.refreshCount, }, process.env.JWT_REFRESH_KEY as string, @@ -54,13 +54,13 @@ async function token(request: UnwrappedRequest): Promise { r: string; } = jwt.verify(refreshCookie, process.env.JWT_REFRESH_KEY as string) as { u: string; r: string }; - if (!(await orm.users.verifyRefreshCount(UserId.fromID(refreshToken.u), refreshToken.r))) { + if (!(await orm.users.verifyRefreshCount(UserId.fromHash(refreshToken.u), refreshToken.r))) { const response = new UnauthorizedResponse('Invalid refresh token'); response.headers.set('Clear-Site-Data', '"cookies","cache","storage","executionContexts"'); return response; } - const claims: Claims | null = await orm.claims.getByUserId(refreshToken.u); + const claims: Claims | null = await orm.claims.getByUserId(UserId.fromHash(refreshToken.u)); const token = jwt.sign({ ...claims }, process.env.JWT_SECRET_KEY as string, { expiresIn: process.env.JWT_LIFESPAN as any, diff --git a/src/orm/claims.ts b/src/orm/claims.ts index 3f18bb1..3e51412 100644 --- a/src/orm/claims.ts +++ b/src/orm/claims.ts @@ -3,30 +3,41 @@ import { ClaimDefinition } from '../utilities/claimDefinitions'; import { UserId } from '../utilities/secureIds'; export class Claims extends ClaimDefinition { - userId?: UserId; + userId: UserId; claims: string[] = []; - constructor(raw?: { userId?: string; claims?: string[] }) { + constructor(raw?: { userId?: string | UserId; claims?: string[] }) { super(); - this.userId = raw?.userId ? UserId.fromHash(raw.userId) : undefined; + if(raw?.userId instanceof UserId) { + this.userId = raw.userId + } else { + this.userId = UserId.fromHash(raw?.userId ?? ''); + } this.claims = raw?.claims ?? []; } - public static test(guardClaim: string, userClaims?: Claims): Boolean { - return userClaims === undefined || userClaims.claims.some((x) => x === guardClaim); + test(...guardClaims: string[]): Boolean { + return Claims.test(this, ...guardClaims); + } + + public static test(userClaims?: Claims, ...guardClaims: string[]): Boolean { + return ( + userClaims === undefined || + userClaims.claims.some((x: string): boolean => guardClaims.some((y: string): boolean => x === y)) + ); } } export class ClaimsOrm { - async getByUserId(userId: string): Promise { + async getByUserId(userId: UserId): Promise { const dbResults: any[] = await sql`SELECT c.name from user_claims as uc JOIN claims as c on uc.claim_id = c.id - where uc.user_id = ${userId};`; - const claims = new Claims(); - claims.userId = UserId.fromID(userId); - claims.claims = dbResults.map((x) => x.name); - return claims; + where uc.user_id = ${userId.raw};`; + return new Claims({ + userId: userId, + claims: dbResults.map((x) => x.name), + }); } async getDefaultClaims(): Promise { diff --git a/src/orm/collections.ts b/src/orm/collections.ts index 9bbc7e9..7036cf1 100644 --- a/src/orm/collections.ts +++ b/src/orm/collections.ts @@ -4,16 +4,18 @@ import { first } from 'lodash'; import { NotFoundError, UnauthorizedError } from '../utilities/errors'; import { UpdateCollectionRequest } from '../utilities/requestModels'; import { Game } from './games'; -import { CollectionId, GameId } from '../utilities/secureIds'; +import { CollectionId, GameId, UserId } from '../utilities/secureIds'; export class Collection { id: CollectionId; name: string; + ownerId: UserId; games: Game[]; - constructor(input: { id: CollectionId; name: string; games?: Game[] }) { + constructor(input: { id: CollectionId; name: string; ownerId:UserId; games?: Game[] }) { this.id = input.id; this.name = input?.name; + this.ownerId = input.ownerId; this.games = input.games ?? []; } } @@ -38,13 +40,13 @@ export class CollectionsOrm { LEFT JOIN collection_games cg ON cg.collection_id = c.id LEFT JOIN games g ON g.id = cg.game_id WHERE c.id = ${id.raw}`; - - if (!(Claims.test(Claims.ADMIN, claims) || Claims.test(Claims.COLLECTIONS.UNOWNED.READ, claims))) { - throw new UnauthorizedError(); - } else if ( - Claims.test(Claims.COLLECTIONS.OWNED.READ, claims) && - claims?.userId && - dbResult?.[0]?.user_id !== claims.userId.raw + if ( + claims && + !( + claims.test(Claims.ADMIN, Claims.COLLECTIONS.UNOWNED.READ) || + (Claims.test(claims, Claims.COLLECTIONS.OWNED.READ) && + dbResult?.[0]?.user_id === claims?.userId?.raw) + ) ) { throw new UnauthorizedError(); } @@ -56,6 +58,7 @@ export class CollectionsOrm { return new Collection({ id: CollectionId.fromID(dbResult[0].collection_id), name: dbResult[0].collection_name, + ownerId: UserId.fromID(dbResult[0].user_id), games: dbResult .filter((x: { game_id: string; game_name: string }) => x.game_id) .map( @@ -69,25 +72,27 @@ export class CollectionsOrm { } async list(claims?: Claims): Promise { - if (!claims || Claims.test(Claims.ADMIN, claims)) { + if (!claims || claims?.test(Claims.ADMIN)) { return (await sql`SELECT * FROM collections`).map( - (x: { id: string; name: string }) => + (x: { id: string; name: string, user_id: string }) => new Collection({ id: CollectionId.fromID(x.id), name: x.name, + ownerId: UserId.fromID(x.user_id) }), ); } - if (!Claims.test(Claims.COLLECTIONS.OWNED.LIST, claims)) { + if (!claims.test(Claims.COLLECTIONS.OWNED.LIST)) { throw new UnauthorizedError(); } return (await sql`SELECT * FROM collections WHERE user_id=${claims.userId?.raw}`).map( - (x: { id: string; name: string }) => + (x: { id: string; name: string; user_id: string }) => new Collection({ id: CollectionId.fromID(x.id), name: x.name, + ownerId: UserId.fromID(x.user_id) }), ); } @@ -95,15 +100,17 @@ export class CollectionsOrm { async update(id: CollectionId, patch: UpdateCollectionRequest, claims?: Claims): Promise { const collection = await this.get(id); - if (!(Claims.test(Claims.ADMIN, claims) || Claims.test(Claims.COLLECTIONS.UNOWNED.UPDATE, claims))) { - throw new UnauthorizedError(); - } else if ( - Claims.test(Claims.COLLECTIONS.OWNED.UPDATE, claims) && - claims?.userId && - collection.id !== claims.userId + if ( + claims && + !( + claims.test(Claims.ADMIN, Claims.COLLECTIONS.UNOWNED.UPDATE) || + (Claims.test(claims, Claims.COLLECTIONS.OWNED.UPDATE) && + collection.ownerId === claims?.userId) + ) ) { throw new UnauthorizedError(); } + collection.name = patch.name ?? collection.name; await sql`UPDATE collections SET name=${collection.name} WHERE id=${id.raw}`; @@ -113,12 +120,14 @@ export class CollectionsOrm { async drop(id: CollectionId, claims?: Claims): Promise { const collection = await this.get(id); - if (!(Claims.test(Claims.ADMIN, claims) || Claims.test(Claims.COLLECTIONS.UNOWNED.DELETE, claims))) { - throw new UnauthorizedError(); - } else if ( - Claims.test(Claims.COLLECTIONS.OWNED.DELETE, claims) && - claims?.userId && - collection.id !== claims.userId + + if ( + claims && + !( + claims.test(Claims.ADMIN, Claims.COLLECTIONS.UNOWNED.DELETE) || + (Claims.test(claims, Claims.COLLECTIONS.OWNED.DELETE) && + collection.ownerId === claims?.userId) + ) ) { throw new UnauthorizedError(); } @@ -130,12 +139,14 @@ export class CollectionsOrm { async addGame(id: CollectionId, gameId: GameId, claims: Claims): Promise { const collection = await this.get(id); - if (!(Claims.test(Claims.ADMIN, claims) || Claims.test(Claims.COLLECTIONS.UNOWNED.GAME.ADD, claims))) { - throw new UnauthorizedError(); - } else if ( - Claims.test(Claims.COLLECTIONS.OWNED.GAME.ADD, claims) && - claims?.userId && - collection.id !== claims.userId + + if ( + claims && + !( + claims.test(Claims.ADMIN) || + (Claims.test(claims, Claims.COLLECTIONS.OWNED.GAME.ADD) && + collection.ownerId === claims?.userId) + ) ) { throw new UnauthorizedError(); } @@ -147,12 +158,14 @@ export class CollectionsOrm { } async removeGame(id: CollectionId, gameId: GameId, claims: Claims): Promise { const collection = await this.get(id); - if (!(Claims.test(Claims.ADMIN, claims) || Claims.test(Claims.COLLECTIONS.UNOWNED.GAME.REMOVE, claims))) { - throw new UnauthorizedError(); - } else if ( - Claims.test(Claims.COLLECTIONS.OWNED.GAME.REMOVE, claims) && - claims?.userId && - collection.id !== claims.userId + + if ( + claims && + !( + claims.test(Claims.ADMIN) || + (Claims.test(claims, Claims.COLLECTIONS.OWNED.GAME.REMOVE) && + collection.ownerId === claims?.userId) + ) ) { throw new UnauthorizedError(); } diff --git a/src/orm/games.ts b/src/orm/games.ts index baf1dd1..74afbfb 100644 --- a/src/orm/games.ts +++ b/src/orm/games.ts @@ -23,7 +23,7 @@ export class Game { export class GamesOrm { async create(model: CreateGameRequest, claims?: Claims): Promise { await sql`INSERT INTO games (name, image_path, bgg_id) - VALUES (${model.name}, ${Claims.test(Claims.GAMES.MANAGE_IMAGES, claims) ? model.imagePath : null}, ${model.bggId})`; + VALUES (${model.name}, ${claims?.test(Claims.GAMES.MANAGE_IMAGES) ? model.imagePath : null}, ${model.bggId})`; const newGameId: string = (first(await sql`SELECT lastval();`) as any)?.lastval as string; return await this.get(GameId.fromID(newGameId)); @@ -54,7 +54,7 @@ export class GamesOrm { gameToUpdate.name = patch.name ?? gameToUpdate.name; gameToUpdate.bggId = patch.bggId ?? gameToUpdate.bggId; - if (Claims.test(Claims.GAMES.MANAGE_IMAGES, claims)) { + if (claims?.test(Claims.GAMES.MANAGE_IMAGES)) { gameToUpdate.imagePath = patch.imagePath ?? gameToUpdate.imagePath; } diff --git a/src/orm/invites.ts b/src/orm/invites.ts index 7c0160e..488d43d 100644 --- a/src/orm/invites.ts +++ b/src/orm/invites.ts @@ -22,7 +22,7 @@ export class InvitesOrm { }, claims?: Claims, ): Promise { - if (!Claims.test(Claims.ADMIN, claims)) { + if (!claims?.test(Claims.ADMIN)) { const userInviteCount = ( first( await sql`SELECT COUNT(*) AS count diff --git a/src/orm/matches.ts b/src/orm/matches.ts index 20c5174..f6e5961 100644 --- a/src/orm/matches.ts +++ b/src/orm/matches.ts @@ -116,10 +116,11 @@ export class MatchOrm { WHERE m.id = ${id.raw}`; if ( + claims && !( - Claims.test(Claims.ADMIN, claims) || - (Claims.test(Claims.MATCHES.OWNED.READ, claims) && dbResult?.[0]?.owner_id === claims?.userId?.raw) || - (Claims.test(Claims.MATCHES.PARTICIPANT.READ, claims) && + claims.test(Claims.ADMIN) || + (claims.test(Claims.MATCHES.OWNED.READ) && dbResult?.[0]?.owner_id === claims?.userId?.raw) || + (claims.test(Claims.MATCHES.PARTICIPANT.READ) && dbResult?.some((x: any) => x.player_id === claims?.userId?.raw)) ) ) { @@ -157,10 +158,8 @@ export class MatchOrm { async drop(id: MatchId, claims?: Claims): Promise { const match = await this.get(id); if ( - !( - Claims.test(Claims.ADMIN, claims) || - (Claims.test(Claims.MATCHES.OWNED.DELETE, claims) && match.owner === claims?.userId) - ) + claims && + !(claims.test(Claims.ADMIN) || (claims.test(Claims.MATCHES.OWNED.DELETE) && match.owner === claims?.userId)) ) { throw new UnauthorizedError(); } diff --git a/src/orm/players.ts b/src/orm/players.ts index 59e0a38..b369bfb 100644 --- a/src/orm/players.ts +++ b/src/orm/players.ts @@ -38,14 +38,15 @@ export class PlayersOrm { } async get(id: PlayerId, claims?: Claims): Promise { - if (!(Claims.test(Claims.ADMIN, claims) || Claims.test(Claims.PLAYERS.OTHER.READ, claims))) { - throw new UnauthorizedError(); - } else if (Claims.test(Claims.PLAYERS.SELF.READ, claims) && claims?.userId) { + if(claims) { const user = await orm.users.get(claims.userId); - if (id.raw !== user.playerId.raw) { + if(!(claims.test(Claims.ADMIN, Claims.PLAYERS.OTHER.READ) || + claims.test(Claims.PLAYERS.SELF.READ) && id === user.playerId)) { throw new UnauthorizedError(); + } } + const dbResult: any = first( await sql`SELECT * FROM players @@ -67,7 +68,7 @@ export class PlayersOrm { } async list(claims?: Claims): Promise { - if (!claims || Claims.test(Claims.ADMIN, claims)) { + if (!claims || claims.test(Claims.ADMIN)) { return (await sql`SELECT * FROM players`).map( (x: { id: string; name: string; elo: string; is_rating_locked: boolean; can_be_multiple: boolean }) => new Player({ @@ -80,7 +81,7 @@ export class PlayersOrm { ); } - if (!Claims.test(Claims.PLAYERS.OTHER.READ, claims)) { + if (!claims.test(Claims.PLAYERS.OTHER.READ)) { throw new UnauthorizedError(); } @@ -109,11 +110,11 @@ export class PlayersOrm { } async update(id: PlayerId, patch: UpdatePlayerRequest, claims?: Claims): Promise { - if (!(Claims.test(Claims.ADMIN, claims) || Claims.test(Claims.PLAYERS.OTHER.UPDATE, claims))) { - throw new UnauthorizedError(); - } else if (Claims.test(Claims.PLAYERS.SELF.UPDATE, claims) && claims?.userId) { + if(claims) { const user = await orm.users.get(claims.userId); - if (id.raw !== user.playerId.raw) { + if(!(claims.test(Claims.ADMIN, Claims.PLAYERS.OTHER.UPDATE) || + (claims.test(Claims.PLAYERS.SELF.UPDATE) && id === user.playerId) + )) { throw new UnauthorizedError(); } } @@ -133,11 +134,11 @@ export class PlayersOrm { } async drop(id: PlayerId, claims?: Claims): Promise { - if (!(Claims.test(Claims.ADMIN, claims) || Claims.test(Claims.PLAYERS.OTHER.DELETE, claims))) { - throw new UnauthorizedError(); - } else if (Claims.test(Claims.PLAYERS.SELF.DELETE, claims) && claims?.userId) { + if(claims) { const user = await orm.users.get(claims.userId); - if (id.raw !== user.playerId.raw) { + if(!(claims.test(Claims.ADMIN, Claims.PLAYERS.OTHER.DELETE) || + (claims.test(Claims.PLAYERS.SELF.DELETE) && id === user.playerId) + )) { throw new UnauthorizedError(); } } diff --git a/src/orm/user.ts b/src/orm/user.ts index 679968c..9527de5 100644 --- a/src/orm/user.ts +++ b/src/orm/user.ts @@ -60,10 +60,10 @@ export class UsersOrm { async get(id: UserId, claims?: Claims): Promise { if ( + claims && !( - Claims.test(Claims.ADMIN, claims) || - Claims.test(Claims.USERS.OTHER.READ, claims) || - (Claims.test(Claims.USERS.SELF.READ, claims) && id === claims?.userId) + claims.test(Claims.ADMIN, Claims.USERS.OTHER.READ) || + (claims.test(Claims.USERS.SELF.READ) && id === claims?.userId) ) ) { throw new UnauthorizedError(); @@ -91,43 +91,35 @@ export class UsersOrm { async update(id: UserId, patch: UpdateUserRequest, claims?: Claims): Promise { if ( + claims && !( - Claims.test(Claims.ADMIN, claims) || - Claims.test(Claims.USERS.OTHER.UPDATE, claims) || - (Claims.test(Claims.USERS.SELF.UPDATE, claims) && id === claims?.userId) + claims.test(Claims.ADMIN, Claims.USERS.OTHER.UPDATE) || + (claims.test(Claims.USERS.SELF.UPDATE) && id === claims?.userId) ) ) { throw new UnauthorizedError(); } const userToUpdate = await this.get(id); - if (Claims.test(Claims.ADMIN, claims)) { + if (!claims || claims.test(Claims.ADMIN)) { userToUpdate.isActive = patch.isActive ?? userToUpdate.isActive; userToUpdate.isAdmin = patch.isAdmin ?? userToUpdate.isAdmin; } - await sql.transaction(async (tx) => { - await tx`UPDATE users + await sql`UPDATE users SET is_active=${userToUpdate.isActive}, is_admin=${userToUpdate.isAdmin} WHERE id = ${id.raw}`; - if (id === claims?.userId && patch.password) { - const passwordHash = await argon2.hash(patch.password); - await tx`UPDATE users - SET pass_hash = ${passwordHash}`; - } - }); - return await this.get(id); } async drop(id: UserId, claims?: Claims): Promise { if ( + claims && !( - Claims.test(Claims.ADMIN, claims) || - Claims.test(Claims.USERS.OTHER.DELETE, claims) || - (Claims.test(Claims.USERS.SELF.DELETE, claims) && id === claims?.userId) + claims.test(Claims.ADMIN, Claims.USERS.OTHER.DELETE) || + (claims.test(Claims.USERS.SELF.DELETE) && id === claims?.userId) ) ) { throw new UnauthorizedError(); @@ -180,8 +172,8 @@ export class UsersOrm { } async changePassword(id: UserId, oldPassword: string | null, newPassword: string, claims?: Claims): Promise { - const isAdmin = Claims.test(Claims.ADMIN, claims); - if (!(isAdmin || (Claims.test(Claims.USERS.SELF.UPDATE, claims) && id === claims?.userId))) { + const isAdmin = claims?.test(Claims.ADMIN) ?? true; + if (!(isAdmin || (claims?.test(Claims.USERS.SELF.UPDATE) && id === claims?.userId))) { throw new UnauthorizedError(); } diff --git a/src/routes/collections.ts b/src/routes/collections.ts index 443956f..a030041 100644 --- a/src/routes/collections.ts +++ b/src/routes/collections.ts @@ -11,14 +11,12 @@ export default { add: { POST: guard(collections.addGame, [ Claims.ADMIN, - Claims.COLLECTIONS.UNOWNED.GAME.ADD, Claims.COLLECTIONS.OWNED.GAME.ADD, ]), }, remove: { POST: guard(collections.removeGame, [ Claims.ADMIN, - Claims.COLLECTIONS.UNOWNED.GAME.REMOVE, Claims.COLLECTIONS.OWNED.GAME.REMOVE, ]), }, diff --git a/src/utilities/claimDefinitions.ts b/src/utilities/claimDefinitions.ts index e97c34c..71b17de 100644 --- a/src/utilities/claimDefinitions.ts +++ b/src/utilities/claimDefinitions.ts @@ -29,49 +29,40 @@ export class ClaimDefinition { }; public static readonly CIRCLES = { PUBLIC: { + READ: 'CIRCLES_OWNED_READ', CREATE: 'CIRCLES_PUBLIC_CREATE', JOIN: 'CIRCLES_PUBLIC_JOIN', - USERS: { - ADD: 'CIRCLES_PUBLIC_USER_ADD', - LIST: 'CIRCLES_PUBLIC_USER_LIST', - INVITE: 'CIRCLES_PUBLIC_USER_INVITE', - }, COMMENTS: { ADD: 'CIRCLES_PUBLIC_COMMENTS_ADD', - DELETE: 'CIRCLES_PUBLIC_COMMENTS_DELETE', + }, + USERS: { + INVITE: 'CIRCLES_OWNED_USER_INVITE', }, }, PRIVATE: { + READ: 'CIRCLES_PRIVATE_READ', + READ_IF_MEMBER: 'CIRCLES_PRIVATE_READ_IF_MEMBER', CREATE: 'CIRCLES_PRIVATE_CREATE', - USERS: { - INVITE: 'CIRCLES_PRIVATE_USER_INVITE', + COMMENTS: { + ADD: 'CIRCLES_PRIVATE_COMMENTS_ADD', }, }, OWNED: { READ: 'CIRCLES_OWNED_READ', UPDATE: 'CIRCLES_OWNED_UPDATE', DELETE: 'CIRCLES_OWNED_DELETE', - USERS: { + PLAYERS: { ADD: 'CIRCLES_OWNED_USER_ADD', LIST: 'CIRCLES_OWNED_USER_LIST', - USERS: { - INVITE: 'CIRCLES_OWNED_USER_INVITE', - }, + }, + USERS: { + INVITE: 'CIRCLES_OWNED_USER_INVITE', }, COMMENTS: { ADD: 'CIRCLES_OWNED_COMMENTS_ADD', DELETE: 'CIRCLES_OWNED_COMMENTS_DELETE', }, }, - UNOWNED: { - READ: 'CIRCLES_UNOWNED_READ', - UPDATE: 'CIRCLES_UNOWNED_UPDATE', - DELETE: 'CIRCLES_UNOWNED_DELETE', - COMMENTS: { - ADD: 'CIRCLES_UNOWNED_COMMENTS_ADD', - DELETE: 'CIRCLES_UNOWNED_COMMENTS_DELETE', - }, - }, }; public static readonly GAMES = { CREATE: 'GAMES_CREATE', @@ -120,10 +111,6 @@ export class ClaimDefinition { READ: 'COLLECTIONS_UNOWNED_READ', UPDATE: 'COLLECTIONS_UNOWNED_UPDATE', DELETE: 'COLLECTIONS_UNOWNED_DELETE', - GAME: { - ADD: 'COLLECTIONS_UNOWNED_GAME_ADD', - REMOVE: 'COLLECTIONS_UNOWNED_GAME_REMOVE', - }, }, }; public static readonly COMMENTS = { diff --git a/src/utilities/guard.ts b/src/utilities/guard.ts index a403477..5694f10 100644 --- a/src/utilities/guard.ts +++ b/src/utilities/guard.ts @@ -23,13 +23,18 @@ export function guard( const authHeader: string | null = (request.headers.get('Authorization')?.replace(/^Bearer /, '') as string) ?? null; try { - const userClaims: Claims = new Claims(jwt.verify(authHeader as string, process.env.JWT_SECRET_KEY as string) as any); - if (!userClaims.claims.some((x: string): boolean => guardedClaims.includes(x))) { + const userClaims: Claims = new Claims( + jwt.verify(authHeader as string, process.env.JWT_SECRET_KEY as string) as any, + ); + if ( + !userClaims.userId.raw || + !userClaims.claims.some((x: string): boolean => guardedClaims.includes(x)) + ) { return new UnauthorizedResponse('Unauthorized'); } return method(await unwrap(request, userClaims)); } catch (error: any) { - console.log(error) + console.log(error); if (error instanceof TokenExpiredError) { return new UnauthorizedResponse(error.message); } diff --git a/src/utilities/requestModels.ts b/src/utilities/requestModels.ts index 9071b7e..3d26d35 100644 --- a/src/utilities/requestModels.ts +++ b/src/utilities/requestModels.ts @@ -14,7 +14,6 @@ export interface CreateUserRequest { export interface UpdateUserRequest { isActive?: boolean; isAdmin?: boolean; - password?: string; } export interface InviteUserRequest { email: string; diff --git a/src/utilities/secureIds.ts b/src/utilities/secureIds.ts index 1894e9c..1faf666 100644 --- a/src/utilities/secureIds.ts +++ b/src/utilities/secureIds.ts @@ -17,7 +17,7 @@ class SecureId { constructor(id: { public?: string; secure?: string }, hashScheme?: HashIds) { this.#hashScheme = hashScheme ?? (this.constructor as any).hashScheme; - if (id.public) { + if (id.public !== undefined) { this.value = id.public; } else if (id.secure) { this.raw = id.secure; @@ -134,3 +134,15 @@ export class MatchId extends SecureId { return super.fromID(id, MatchId); } } + +export class CircleId extends SecureId { + protected static override hashPrefix: string = 'CircleId'; + + public static fromHash(hash: string): CircleId { + return super.fromHash(hash, CircleId); + } + + public static fromID(id: string): CircleId { + return super.fromID(id, CircleId); + } +}