Skip to content

Commit f7e9e0e

Browse files
committed
support for multiple versions in otps
1 parent 942bd38 commit f7e9e0e

8 files changed

Lines changed: 65 additions & 9 deletions

src/modules/games/game-versions.controller.spec.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,12 @@ describe("GameVersionsController", () => {
6868
"bytes=0-999",
6969
);
7070

71-
expect(otpService.create).toHaveBeenCalledWith("testuser", 42, 1024);
71+
expect(otpService.create).toHaveBeenCalledWith(
72+
"testuser",
73+
42,
74+
7,
75+
1024,
76+
);
7277
expect(mockResponse.setHeader).toHaveBeenCalledWith("X-Otp", "mock-otp");
7378
expect(filesService.download).toHaveBeenCalledWith(
7479
mockResponse,

src/modules/games/game-versions.controller.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,12 @@ export class GameVersionsController {
9393
): Promise<StreamableFile> {
9494
response.setHeader(
9595
"X-Otp",
96-
this.otpService.create(request.user.username, gameId, Number(speedlimit)),
96+
this.otpService.create(
97+
request.user.username,
98+
gameId,
99+
versionId,
100+
Number(speedlimit),
101+
),
97102
);
98103

99104
return this.filesService.download(

src/modules/games/games.controller.spec.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,12 @@ describe("GamesController", () => {
155155
"bytes=0-999",
156156
);
157157

158-
expect(otpService.create).toHaveBeenCalledWith("testuser", 42, 1024);
158+
expect(otpService.create).toHaveBeenCalledWith(
159+
"testuser",
160+
42,
161+
undefined,
162+
1024,
163+
);
159164
expect(mockResponse.setHeader).toHaveBeenCalledWith("X-Otp", "mock-otp");
160165
expect(filesService.download).toHaveBeenCalledWith(
161166
mockResponse,

src/modules/games/games.controller.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ export class GamesController {
392392
this.otpService.create(
393393
request.user.username,
394394
Number(params.game_id),
395+
undefined,
395396
Number(speedlimit),
396397
),
397398
);

src/modules/otp/models/otp.model.spec.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import Otp from "./otp.model";
22

33
describe("Otp Model", () => {
44
it("should create an OTP with all properties", () => {
5-
const otp = new Otp("abc123", "testuser", 42, 1024);
5+
const otp = new Otp("abc123", "testuser", 42, 7, 1024);
66
expect(otp.otp).toBe("abc123");
77
expect(otp.username).toBe("testuser");
88
expect(otp.gameId).toBe(42);
9+
expect(otp.versionId).toBe(7);
910
expect(otp.xDownloadSpeedLimit).toBe(1024);
1011
expect(otp.createdAt).toBeInstanceOf(Date);
1112
expect(otp.expiresAt).toBeInstanceOf(Date);
@@ -28,16 +29,18 @@ describe("Otp Model", () => {
2829
it("should create an OTP without optional parameters", () => {
2930
const otp = new Otp("abc123", "testuser");
3031
expect(otp.gameId).toBeUndefined();
32+
expect(otp.versionId).toBeUndefined();
3133
expect(otp.xDownloadSpeedLimit).toBeUndefined();
3234
});
3335

3436
describe("getLoggableData", () => {
3537
it("should redact the OTP value", () => {
36-
const otp = new Otp("secret-value", "testuser", 42, 1024);
38+
const otp = new Otp("secret-value", "testuser", 42, 7, 1024);
3739
const loggable = otp.getLoggableData();
3840
expect(loggable.otp).toBe("**REDACTED**");
3941
expect(loggable.username).toBe("testuser");
4042
expect(loggable.gameId).toBe(42);
43+
expect(loggable.versionId).toBe(7);
4144
expect(loggable.xDownloadSpeedLimit).toBe(1024);
4245
expect(loggable.createdAt).toBeInstanceOf(Date);
4346
expect(loggable.expiresAt).toBeInstanceOf(Date);

src/modules/otp/models/otp.model.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,20 @@ export default class Otp {
44
createdAt: Date = new Date();
55
expiresAt: Date = new Date(Date.now() + 5 * 60 * 1000); // 5 Minutes
66
gameId?: number;
7+
versionId?: number;
78
xDownloadSpeedLimit?: number;
89

910
constructor(
1011
otp: string,
1112
username: string,
1213
gameId?: number,
14+
versionId?: number,
1315
xDownloadSpeedLimit?: number,
1416
) {
1517
this.otp = otp;
1618
this.username = username;
1719
this.gameId = gameId;
20+
this.versionId = versionId;
1821
this.xDownloadSpeedLimit = xDownloadSpeedLimit;
1922
}
2023

@@ -25,6 +28,7 @@ export default class Otp {
2528
createdAt: this.createdAt,
2629
expiresAt: this.expiresAt,
2730
gameId: this.gameId,
31+
versionId: this.versionId,
2832
xDownloadSpeedLimit: this.xDownloadSpeedLimit,
2933
};
3034
}

src/modules/otp/otp.service.spec.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ describe("OtpService", () => {
1616

1717
describe("create", () => {
1818
it("should create an OTP and return the token string", () => {
19-
const result = service.create("testuser", 42, 1024);
19+
const result = service.create("testuser", 42, 7, 1024);
2020
expect(result).toBeDefined();
2121
expect(typeof result).toBe("string");
2222
expect(result.length).toBeGreaterThan(0);
@@ -38,14 +38,17 @@ describe("OtpService", () => {
3838
describe("get", () => {
3939
it("should validate and consume a valid OTP", async () => {
4040
const mockResponse = { setHeader: jest.fn() } as any;
41-
const otp = service.create("testuser", 42, 1024);
41+
const otp = service.create("testuser", 42, 7, 1024);
4242
filesService.download.mockResolvedValue({} as any);
4343

4444
await service.get(otp, mockResponse);
4545
expect(filesService.download).toHaveBeenCalledWith(
4646
mockResponse,
4747
42,
48+
7,
4849
1024,
50+
undefined,
51+
undefined,
4952
);
5053
});
5154

@@ -86,14 +89,34 @@ describe("OtpService", () => {
8689

8790
it("should pass download speed limit to filesService", async () => {
8891
const mockResponse = { setHeader: jest.fn() } as any;
89-
const otp = service.create("testuser", 99, 2048);
92+
const otp = service.create("testuser", 99, undefined, 2048);
9093
filesService.download.mockResolvedValue({} as any);
9194

9295
await service.get(otp, mockResponse);
9396
expect(filesService.download).toHaveBeenCalledWith(
9497
mockResponse,
9598
99,
99+
undefined,
96100
2048,
101+
undefined,
102+
undefined,
103+
);
104+
});
105+
106+
it("should bind OTP download to the requested version id", async () => {
107+
const mockResponse = { setHeader: jest.fn() } as any;
108+
const otp = service.create("testuser", 101, 33, 4096);
109+
filesService.download.mockResolvedValue({} as any);
110+
111+
await service.get(otp, mockResponse);
112+
113+
expect(filesService.download).toHaveBeenCalledWith(
114+
mockResponse,
115+
101,
116+
33,
117+
4096,
118+
undefined,
119+
undefined,
97120
);
98121
});
99122
});

src/modules/otp/otp.service.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,17 @@ export class OtpService {
3030
public create(
3131
username: string,
3232
gameId?: number,
33+
versionId?: number,
3334
xDownloadSpeedLimit?: number,
3435
): string {
3536
const randomOtp = randomBytes(64).toString("hex");
36-
const otp = new Otp(randomOtp, username, gameId, xDownloadSpeedLimit);
37+
const otp = new Otp(
38+
randomOtp,
39+
username,
40+
gameId,
41+
versionId,
42+
xDownloadSpeedLimit,
43+
);
3744
this.otps.set(randomOtp, otp);
3845
this.logger.log("OTP Created.", otp.getLoggableData());
3946
return randomOtp;
@@ -52,7 +59,10 @@ export class OtpService {
5259
return this.filesService.download(
5360
response,
5461
existingOtp.gameId,
62+
existingOtp.versionId,
5563
existingOtp.xDownloadSpeedLimit,
64+
undefined,
65+
undefined,
5666
);
5767
}
5868
}

0 commit comments

Comments
 (0)