Skip to content

Commit

Permalink
support for updating token
Browse files Browse the repository at this point in the history
  • Loading branch information
mrosack committed Dec 17, 2024
1 parent 5b17a72 commit a78e5af
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 15 deletions.
37 changes: 33 additions & 4 deletions api/controllers/authController.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import * as querystring from 'querystring';
import { Get, Request, Route, Tags } from 'tsoa';
import { Get, Request, Response, Route, Security, Tags } from 'tsoa';

import { JwtUtil } from '../../lib/auth/jwtUtil';
import { IUserRepository, USER_REPOSITORY_SYMBOL } from '../../lib/dynamoose/userRepository';
import { inject, provideSingleton } from '../../lib/ioc';
import { pydtLogger } from '../../lib/logging';
import { SteamProfile, User } from '../../lib/models';
import { steamPassport } from '../../lib/steamUtil';
import { HttpRequest, HttpResponseError } from '../framework';
import { ErrorResponse, HttpRequest, HttpResponseError } from '../framework';
import {
IPrivateUserDataRepository,
PRIVATE_USER_DATA_REPOSITORY_SYMBOL
} from '../../lib/dynamoose/privateUserDataRepository';

@Route('auth')
@Tags('auth')
@provideSingleton(AuthController)
export class AuthController {
constructor(@inject(USER_REPOSITORY_SYMBOL) private userRepository: IUserRepository) {}
constructor(
@inject(USER_REPOSITORY_SYMBOL) private userRepository: IUserRepository,
@inject(PRIVATE_USER_DATA_REPOSITORY_SYMBOL) private pudRepository: IPrivateUserDataRepository
) {}

@Get('steam')
public authenticate(@Request() request: HttpRequest): Promise<AuthenticateResponse> {
Expand Down Expand Up @@ -53,6 +60,22 @@ export class AuthController {
});
}

@Get('auth/updateTokenNonce')
@Security('api_key')
@Response<ErrorResponse>(401, 'Unauthorized')
public async updateTokenNonce(@Request() request: HttpRequest): Promise<string> {
const pud = await this.pudRepository.get(request.user);

pud.tokenNonce = (pud.tokenNonce || 0) + 1;

await this.pudRepository.saveVersioned(pud);

return JwtUtil.createToken({
steamId: request.user,
nonce: pud.tokenNonce
});
}

@Get('steam/validate')
public validate(@Request() request: HttpRequest): Promise<ValidateResponse> {
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -96,8 +119,14 @@ export class AuthController {
return this.userRepository.saveVersioned(dbUser);
})
.then(() => {
return this.pudRepository.get(user.profile.id);
})
.then(pud => {
resolve({
token: JwtUtil.createToken(user.profile.id),
token: JwtUtil.createToken({
steamId: user.profile.id,
nonce: pud.tokenNonce
}),
steamProfile: user.profile._json
});
})
Expand Down
8 changes: 6 additions & 2 deletions api/websocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { JwtUtil } from '../lib/auth/jwtUtil';
import { loggingHandler, pydtLogger } from '../lib/logging';
import { IWebsocketProvider, WEBSOCKET_PROVIDER_SYMBOL } from '../lib/websocketProvider';
import { LambdaProxyEvent } from './framework';
import { validateNonce } from '../lib/auth/expressAuthentication';

export const handler = loggingHandler(async (event: LambdaProxyEvent, context, iocContainer) => {
const doug = iocContainer.resolve(WebsocketHandler);
Expand All @@ -27,8 +28,11 @@ export class WebsocketHandler {

case 'auth':
// validate token and tie user to connection
const steamId = JwtUtil.parseToken(body);
await this.wsProvider.registerUser(steamId, connectionId);
const data = JwtUtil.parseToken(body);

await validateNonce(data);

await this.wsProvider.registerUser(data.steamId, connectionId);
break;

case '$disconnect':
Expand Down
23 changes: 19 additions & 4 deletions lib/auth/expressAuthentication.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
import { HttpRequest, HttpResponseError } from '../../api/framework/index';
import { Config } from '../config';
import { PrivateUserDataRepository } from '../dynamoose/privateUserDataRepository';
import { iocContainer } from '../ioc';
import { pydtLogger } from '../logging';
import { JwtUtil } from './jwtUtil';
import { JwtData, JwtUtil } from './jwtUtil';

export async function validateNonce(data: JwtData) {
const pudRepo = iocContainer.resolve(PrivateUserDataRepository);
const pud = await pudRepo.get(data.steamId);

if ((pud.tokenNonce || -1) !== (data.nonce || -1)) {
pydtLogger.warn(`Nonce mismatch: ${pud.tokenNonce} vs ${data.nonce}`);
throw HttpResponseError.createUnauthorized();
}
}

export async function expressAuthentication(
request: HttpRequest,
Expand All @@ -14,11 +26,14 @@ export async function expressAuthentication(
if (securityName === 'api_key') {
try {
if (request.headers && request.headers['authorization']) {
const steamId = JwtUtil.parseToken(request.headers['authorization']);
const data = JwtUtil.parseToken(request.headers['authorization']);

await validateNonce(data);

if (!Config.runningLocal) {
request.subSegment.addAnnotation('user', steamId);
request.subSegment.addAnnotation('user', data.steamId);
}
return steamId;
return data.steamId;
}
} catch (e) {
pydtLogger.warn('Error parsing JWT token', e);
Expand Down
21 changes: 17 additions & 4 deletions lib/auth/jwtUtil.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
import * as jwt from 'jsonwebtoken';
import { Config } from '../config';

export type JwtData = {
steamId: string;
nonce?: number;
};

export class JwtUtil {
public static createToken(steamId: string): string {
return jwt.sign(steamId, Config.jwtSecret);
public static createToken(data: JwtData): string {
return jwt.sign(data, Config.jwtSecret);
}

public static parseToken(token: string): string {
return jwt.verify(token, Config.jwtSecret);
public static parseToken(token: string): JwtData {
const data = jwt.verify(token, Config.jwtSecret);

if (!data.steamId) {
return {
steamId: data
};
}

return data;
}
}
3 changes: 2 additions & 1 deletion lib/dynamoose/privateUserDataRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ export class PrivateUserDataRepository
schema: [String]
},
newGameEmailFilter: String,
lastTurnIpAddress: String
lastTurnIpAddress: String,
tokenNonce: Number
});
}

Expand Down
1 change: 1 addition & 0 deletions lib/models/privateUserData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface PrivateUserData {
newGameEmailTypes?: string[];
newGameEmailFilter?: string;
lastTurnIpAddress?: string;
tokenNonce?: number;
}

export interface WebPushSubscription {
Expand Down

0 comments on commit a78e5af

Please sign in to comment.