Skip to content
This repository has been archived by the owner on Aug 22, 2024. It is now read-only.

Commit

Permalink
merge with master
Browse files Browse the repository at this point in the history
  • Loading branch information
tpdewolf committed May 15, 2024
2 parents b7c1f5b + fa5ab45 commit 7c3e6c0
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 37 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ ACCESS_TOKEN_EXPIRES_IN=5m
SESSION_MAX_AGE=1d
SESSION_MAX_INACTIVE=30m
SESSION_STORAGE=redis
SESSION_EXPIRE_ON_BROWSER_RESTART=true
REDIS_URL=redis://localhost:6379
29 changes: 24 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,11 @@ TODO

You can configure the services through these environment variables:

| Variable | Usage |
| -------------- | --------------------------------------------------------------------------------------------------------- |
| `LOG_REQUESTS` | If set to `true` or `1`, all HTTP requests are logged to stdout. |
| `PORT` | Port number to run the service on. Defaults to `3000`. The the Docker image sets this to `80` by default. | ` |
| Variable | Usage |
| ---------------- | --------------------------------------------------------------------------------------------------------- |
| `LOG_REQUESTS` | If set to `true` or `1`, all HTTP requests are logged to stdout. |
| `PORT` | Port number to run the service on. Defaults to `3000`. The the Docker image sets this to `80` by default. | ` |
| `SESSION_EXPIRE_ON_BROWSER_RESTART` | If set to `true` or `1`, the session will be only valid in a browser session because the cookies will be saved as a session cookie |


## FAQ
Expand All @@ -74,7 +75,25 @@ Example:
```
openssl genpkey -algorithm RSA -aes-256-cbc -outform PEM -out private_key.pem -pkeyopt rsa_keygen_bits:2048
```
For explanation of the options check the [OpenSSL documentation](https://www.openssl.org/docs/man1.1.0/man1/genpkey.html#KEY-GENERATION-OPTIONS])
For explanation of the options check the [OpenSSL documentation](https://www.openssl.org/docs/man1.1.1/man1/openssl-genpkey.html#KEY-GENERATION-OPTIONS)


#### Alternative way to generate a key
Run in terminal:
```brew install mkcert`

Then type:
```mkcert -install```

Followed by:
```mkcert yourSiteName```

Replace `yourSiteName` with any name of your website. For example: download-site-acc

This will generate 2 files: `{yourSiteName}.pem` and `{yourSiteName}-key.pem`.

Now base64 encode the file and you have your base64 encoded signing key.
```cat `{yourSiteName}-key.pem | base64```

## Maintainers

Expand Down
20 changes: 10 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"node-fetch": "^2.6.1",
"node-jose": "^2.0.0",
"randomstring": "^1.1.5",
"redis": "^3.0.2"
"redis": "^3.1.2"
},
"devDependencies": {
"@types/jsonwebtoken": "^8.5.0",
Expand Down
11 changes: 7 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import * as querystring from "querystring";
import * as Cookies from "cookies";
import ms = require("ms");

import { noCache } from "./middleware/no-cache";
import { loadKeystore } from "./util/keystore";
import { jwtSession } from "./middleware/jwt-session";
import { redisSession } from "./middleware/redis-session";
Expand Down Expand Up @@ -160,8 +161,8 @@ app.proxy = true;
const stateCookie = ctx.cookies.get(stateCookieName);

// Clear the state cookies.
ctx.cookies.set("oidc_state_last");
ctx.cookies.set(stateCookieName);
ctx.cookies.set("oidc_state_last", null, defaultCookieOptions);
ctx.cookies.set(stateCookieName, null, defaultCookieOptions);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
let stateData: any;
Expand Down Expand Up @@ -265,7 +266,7 @@ app.proxy = true;
const redirectUri = ctx.cookies.get(cookieName);

if (redirectUri) {
ctx.cookies.set(cookieName);
ctx.cookies.set(cookieName, null, defaultCookieOptions);
ctx.redirect(redirectUri);
}
ctx.body = "You are logged out";
Expand Down Expand Up @@ -295,7 +296,6 @@ app.proxy = true;
})
);
app.use(json());
app.use(statusRouter.routes()).use(statusRouter.allowedMethods());

const sessionStorage = process.env.SESSION_STORAGE ?? "jwt";
switch (sessionStorage) {
Expand All @@ -310,7 +310,10 @@ app.proxy = true;
`Invalid value for SESSION_STORAGE: ${sessionStorage}. Expect jwt,redis`
);
}

app.use(noCache());
app.use(appSession({ keystore }));
app.use(statusRouter.routes()).use(statusRouter.allowedMethods());
app.use(router.routes()).use(router.allowedMethods());

const port = parseInt(process.env.PORT ?? "3000");
Expand Down
3 changes: 2 additions & 1 deletion src/middleware/csrf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ export function csrfOrAccessTokenAuth(
return async (ctx, next) => {
if (
ctx.get("Authorization") ===
`Bearer ${ctx.state.appSession.csrfToken}`
`Bearer ${ctx.state.appSession.csrfToken}` ||
ctx.query.token === ctx.state.appSession.csrfToken
) {
await next();
return;
Expand Down
25 changes: 17 additions & 8 deletions src/middleware/jwt-session.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as Koa from "koa";
import * as Cookies from "cookies";
import * as jose from "node-jose";
import * as jwtPromise from "../util/jwt-promise";
import { JwtHeader, SigningKeyCallback, SignOptions } from "jsonwebtoken";
Expand Down Expand Up @@ -131,6 +132,9 @@ export function jwtSession(
const tokenExpiresIn = process.env.SESSION_MAX_AGE ?? "1d";
const algorithm = process.env.SESSION_SIGNATURE_ALGORITHM ?? "RS256";
const cookieSecure = isTruthy(process.env.COOKIES_SECURE ?? "true");
const sessionExpireOnBrowserRestart = isTruthy(
process.env.SESSION_EXPIRE_ON_BROWSER_RESTART ?? "true"
);
const sameSite = isTruthy(process.env.COOKIES_SECURE ?? "true")
? "none"
: "lax";
Expand Down Expand Up @@ -161,25 +165,30 @@ export function jwtSession(

await next();

const defaultCookieOptions: Cookies.SetOption = {
secure: cookieSecure,
httpOnly: true,
sameSite,
};

// Store data back into cookies.
const newCookieData = await sessionHandler.getTokenCookieData();
if (newCookieData) {
const { headerPayload, signature } = newCookieData;
ctx.cookies.set(cookieName, headerPayload, {
secure: cookieSecure,
httpOnly: true,
...defaultCookieOptions,
maxAge: cookieMaxAge,
sameSite,
});
ctx.cookies.set(signatureCookieName, signature, {
secure: cookieSecure,
httpOnly: true,
sameSite,
...defaultCookieOptions,
...(sessionExpireOnBrowserRestart
? {}
: { maxAge: cookieMaxAge }),
});
} else if (cookieHeaderPayload && cookieSignature) {
// Clear the cookies.
ctx.cookies.set(cookieName);
ctx.cookies.set(signatureCookieName);
ctx.cookies.set(cookieName, null, defaultCookieOptions);
ctx.cookies.set(signatureCookieName, null, defaultCookieOptions);
}
};
}
10 changes: 10 additions & 0 deletions src/middleware/no-cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as Koa from "koa";

export function noCache(): Koa.Middleware {
return async (ctx, next) => {
await next();
ctx.set("Cache-Control", "no-store, no-cache, must-revalidate");
ctx.set("Pragma", "no-cache");
ctx.set("Expires", "0");
};
}
25 changes: 17 additions & 8 deletions src/middleware/redis-session.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as Koa from "koa";
import * as Cookies from "cookies";
import * as randomstring from "randomstring";
import { createClient, RedisClient } from "redis";
import ms = require("ms");
Expand Down Expand Up @@ -109,6 +110,9 @@ export function redisSession(): Koa.Middleware<ClientSessionState> {
const cookieMaxAge = ms(process.env.SESSION_MAX_INACTIVE ?? "30m");
const sessionExpiresIn = process.env.SESSION_MAX_AGE ?? "1d";
const cookieSecure = isTruthy(process.env.COOKIES_SECURE ?? "true");
const sessionExpireOnBrowserRestart = isTruthy(
process.env.SESSION_EXPIRE_ON_BROWSER_RESTART ?? "true"
);
const sameSite = isTruthy(process.env.COOKIES_SECURE ?? "true")
? "none"
: "lax";
Expand Down Expand Up @@ -148,25 +152,30 @@ export function redisSession(): Koa.Middleware<ClientSessionState> {
await next();
await sessionHandler.storeData();

const defaultCookieOptions: Cookies.SetOption = {
secure: cookieSecure,
httpOnly: true,
sameSite,
};

// Store data back into cookies.
const newCookieData = await sessionHandler.getTokenCookieData();
if (newCookieData) {
const { payload, signature } = newCookieData;
ctx.cookies.set(cookieName, payload, {
secure: cookieSecure,
httpOnly: true,
...defaultCookieOptions,
maxAge: cookieMaxAge,
sameSite,
});
ctx.cookies.set(signatureCookieName, signature, {
secure: cookieSecure,
httpOnly: true,
sameSite,
...defaultCookieOptions,
...(sessionExpireOnBrowserRestart
? {}
: { maxAge: cookieMaxAge }),
});
} else if (cookiePayload && cookieSignature) {
// Clear the cookies.
ctx.cookies.set(cookieName);
ctx.cookies.set(signatureCookieName);
ctx.cookies.set(cookieName, null, defaultCookieOptions);
ctx.cookies.set(signatureCookieName, null, defaultCookieOptions);
}
};
}

0 comments on commit 7c3e6c0

Please sign in to comment.