Skip to content

Commit aea383e

Browse files
committed
feat: add csrf support to api & web components
1 parent 03e2fee commit aea383e

File tree

7 files changed

+29
-3
lines changed

7 files changed

+29
-3
lines changed

api/src/unraid-api/auth/auth.service.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { AuthZService } from 'nest-authz';
44

55
import type { UserAccount } from '@app/graphql/generated/api/types';
66
import { Role } from '@app/graphql/generated/api/types';
7+
import { getters } from '@app/store';
78
import { handleAuthError } from '@app/utils';
89

910
import { ApiKeyService } from './api-key.service';
@@ -205,6 +206,10 @@ export class AuthService {
205206
}
206207
}
207208

209+
public validateCsrfToken(token?: string): boolean {
210+
return Boolean(token) && token === getters.emhttp().var.csrfToken;
211+
}
212+
208213
/**
209214
* Returns a user object representing a session.
210215
* Note: Does NOT perform validation.

api/src/unraid-api/auth/cookie.strategy.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ export class UserCookieStrategy extends PassportStrategy(Strategy, strategyName)
1818
}
1919

2020
public validate = async (req: CustomRequest): Promise<any> => {
21-
return this.authService.validateCookiesCasbin(req.cookies);
21+
return (
22+
this.authService.validateCsrfToken(req.headers['x-csrf-token']) &&
23+
this.authService.validateCookiesCasbin(req.cookies)
24+
);
2225
};
2326
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
import type { FastifyRequest } from '@app/types/fastify';
22

3-
export interface CustomRequest extends FastifyRequest {}
3+
export interface CustomRequest extends FastifyRequest {
4+
headers: FastifyRequest['headers'] & { 'x-csrf-token'?: string };
5+
}

web/.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ VITE_ALLOW_CONSOLE_LOGS=true
1010
# For an Unraid Webgui deployment, set this to 10.
1111
VITE_TAILWIND_BASE_FONT_SIZE=16
1212
VITE_WEBGUI=http://localhost:3001
13+
# static override for csrf token during development.
14+
VITE_CSRF_TOKEN="0000000000000000"

web/helpers/create-apollo-client.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ const httpEndpoint = WEBGUI_GRAPHQL;
2020
const wsEndpoint = new URL(WEBGUI_GRAPHQL.toString().replace('http', 'ws'));
2121

2222
// const headers = { 'x-api-key': serverStore.apiKey };
23-
const headers = {};
23+
const headers = {
24+
'x-csrf-token': globalThis.csrf_token,
25+
};
2426

2527
const httpLink = createHttpLink({
2628
uri: httpEndpoint.toString(),

web/helpers/globals.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
declare global {
2+
// eslint-disable-next-line no-var
3+
var csrf_token: string;
4+
}
5+
6+
// an export or import statement is required to make this file a module
7+
export {};

web/helpers/urls.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ const DOCS_REGISTRATION_REPLACE_KEY = new URL('/go/changing-the-flash-device/',
2929

3030
const SUPPORT = new URL('https://unraid.net');
3131

32+
// initialize csrf_token in nuxt playground
33+
if (import.meta.env.VITE_CSRF_TOKEN) {
34+
globalThis.csrf_token = import.meta.env.VITE_CSRF_TOKEN;
35+
}
36+
3237
export {
3338
ACCOUNT,
3439
ACCOUNT_CALLBACK,

0 commit comments

Comments
 (0)