fix(realtime): Allow connections for guest users

Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
Tilman Vatteroth 2022-10-03 18:39:44 +02:00
parent 4ab66dfe2d
commit a97f7e8fd1
8 changed files with 139 additions and 59 deletions

View file

@ -129,9 +129,9 @@ describe('SessionService', () => {
const mockedRequest = Mock.of<IncomingMessage>({
headers: {},
});
expect(() =>
sessionService.extractVerifiedSessionIdFromRequest(mockedRequest),
).toThrow('No hedgedoc-session cookie found');
expect(
sessionService.extractSessionIdFromRequest(mockedRequest).isEmpty(),
).toBeTruthy();
});
it("fails if the cookie header isn't valid", () => {
@ -139,9 +139,9 @@ describe('SessionService', () => {
headers: { cookie: 'no' },
});
mockParseCookieModule(`s:anyValidSessionId.validSignature`);
expect(() =>
sessionService.extractVerifiedSessionIdFromRequest(mockedRequest),
).toThrow('No hedgedoc-session cookie found');
expect(
sessionService.extractSessionIdFromRequest(mockedRequest).isEmpty(),
).toBeTruthy();
});
it("fails if the hedgedoc session cookie isn't marked as signed", () => {
@ -150,8 +150,10 @@ describe('SessionService', () => {
});
mockParseCookieModule('sessionId.validSignature');
expect(() =>
sessionService.extractVerifiedSessionIdFromRequest(mockedRequest),
).toThrow("cookie doesn't look like a signed cookie");
sessionService.extractSessionIdFromRequest(mockedRequest),
).toThrow(
'cookie "hedgedoc-session" doesn\'t look like a signed session cookie',
);
});
it("fails if the hedgedoc session cookie doesn't contain a session id", () => {
@ -160,8 +162,10 @@ describe('SessionService', () => {
});
mockParseCookieModule('s:.validSignature');
expect(() =>
sessionService.extractVerifiedSessionIdFromRequest(mockedRequest),
).toThrow("cookie doesn't look like a signed cookie");
sessionService.extractSessionIdFromRequest(mockedRequest),
).toThrow(
'cookie "hedgedoc-session" doesn\'t look like a signed session cookie',
);
});
it("fails if the hedgedoc session cookie doesn't contain a signature", () => {
@ -170,8 +174,10 @@ describe('SessionService', () => {
});
mockParseCookieModule('s:sessionId.');
expect(() =>
sessionService.extractVerifiedSessionIdFromRequest(mockedRequest),
).toThrow("cookie doesn't look like a signed cookie");
sessionService.extractSessionIdFromRequest(mockedRequest),
).toThrow(
'cookie "hedgedoc-session" doesn\'t look like a signed session cookie',
);
});
it("fails if the hedgedoc session cookie isn't signed correctly", () => {
@ -180,8 +186,8 @@ describe('SessionService', () => {
});
mockParseCookieModule('s:sessionId.invalidSignature');
expect(() =>
sessionService.extractVerifiedSessionIdFromRequest(mockedRequest),
).toThrow("Signature of hedgedoc-session cookie isn't valid.");
sessionService.extractSessionIdFromRequest(mockedRequest),
).toThrow('signature of cookie "hedgedoc-session" isn\'t valid.');
});
it('can extract a session id from a valid request', () => {
@ -190,7 +196,7 @@ describe('SessionService', () => {
});
mockParseCookieModule(`s:${validSessionId}.validSignature`);
expect(
sessionService.extractVerifiedSessionIdFromRequest(mockedRequest),
sessionService.extractSessionIdFromRequest(mockedRequest).get(),
).toBe(validSessionId);
});
});

View file

@ -70,27 +70,37 @@ export class SessionService {
* Extracts the hedgedoc session cookie from the given {@link IncomingMessage request} and checks if the signature is correct.
*
* @param request The http request that contains a session cookie
* @return The extracted session id
* @throws Error if no session cookie was found
* @throws Error if the cookie content is malformed
* @throws Error if the cookie content isn't signed
* @return An {@link Optional optional} that either contains the extracted session id or is empty if no session cookie has been found
* @throws Error if the cookie has been found but the content is malformed
* @throws Error if the cookie has been found but the content isn't signed
*/
extractVerifiedSessionIdFromRequest(request: IncomingMessage): string {
return Optional.ofNullable(request.headers.cookie)
extractSessionIdFromRequest(request: IncomingMessage): Optional<string> {
return Optional.ofNullable(request.headers?.cookie)
.map((cookieHeader) => parseCookie(cookieHeader)[HEDGEDOC_SESSION])
.orThrow(() => new Error(`No ${HEDGEDOC_SESSION} cookie found`))
.map((cookie) => SessionService.sessionCookieContentRegex.exec(cookie))
.orThrow(
() =>
new Error(
`${HEDGEDOC_SESSION} cookie doesn't look like a signed cookie`,
),
)
.guard(
(cookie) => unsign(cookie[1], this.authConfig.session.secret) !== false,
() => new Error(`Signature of ${HEDGEDOC_SESSION} cookie isn't valid.`),
)
.map((cookie) => cookie[2])
.get();
.map((rawCookie) =>
this.extractVerifiedSessionIdFromCookieContent(rawCookie),
);
}
/**
* Parses the given session cookie content and extracts the session id.
*
* @param rawCookie The cookie to parse
* @return The extracted session id
* @throws Error if the cookie has been found but the content is malformed
* @throws Error if the cookie has been found but the content isn't signed
*/
private extractVerifiedSessionIdFromCookieContent(rawCookie: string): string {
const parsedCookie =
SessionService.sessionCookieContentRegex.exec(rawCookie);
if (parsedCookie === null) {
throw new Error(
`cookie "${HEDGEDOC_SESSION}" doesn't look like a signed session cookie`,
);
}
if (unsign(parsedCookie[1], this.authConfig.session.secret) === false) {
throw new Error(`signature of cookie "${HEDGEDOC_SESSION}" isn't valid.`);
}
return parsedCookie[2];
}
}