mirror of
https://github.com/wukko/cobalt.git
synced 2025-06-13 05:37:44 +02:00
api: bind session tokens to ip hash
This commit is contained in:
@ -175,7 +175,7 @@ export const runAPI = async (express, app, __dirname, isPrimary = true) => {
|
||||
return fail(res, "error.api.auth.jwt.invalid");
|
||||
}
|
||||
|
||||
if (!jwt.verify(token)) {
|
||||
if (!jwt.verify(token, getIP(req, 32))) {
|
||||
return fail(res, "error.api.auth.jwt.invalid");
|
||||
}
|
||||
|
||||
@ -221,7 +221,7 @@ export const runAPI = async (express, app, __dirname, isPrimary = true) => {
|
||||
}
|
||||
|
||||
try {
|
||||
res.json(jwt.generate());
|
||||
res.json(jwt.generate(getIP(req, 32)));
|
||||
} catch {
|
||||
return fail(res, "error.api.generic");
|
||||
}
|
||||
|
@ -82,14 +82,13 @@ export function normalizeRequest(request) {
|
||||
));
|
||||
}
|
||||
|
||||
export function getIP(req) {
|
||||
export function getIP(req, prefix = 56) {
|
||||
const strippedIP = req.ip.replace(/^::ffff:/, '');
|
||||
const ip = ipaddr.parse(strippedIP);
|
||||
if (ip.kind() === 'ipv4') {
|
||||
return strippedIP;
|
||||
}
|
||||
|
||||
const prefix = 56;
|
||||
const v6Bytes = ip.toByteArray();
|
||||
v6Bytes.fill(0, prefix / 8);
|
||||
|
||||
|
@ -6,12 +6,19 @@ import { env } from "../config.js";
|
||||
const toBase64URL = (b) => Buffer.from(b).toString("base64url");
|
||||
const fromBase64URL = (b) => Buffer.from(b, "base64url").toString();
|
||||
|
||||
const makeHmac = (header, payload) =>
|
||||
createHmac("sha256", env.jwtSecret)
|
||||
.update(`${header}.${payload}`)
|
||||
.digest("base64url");
|
||||
const makeHmac = (data) => {
|
||||
return createHmac("sha256", env.jwtSecret)
|
||||
.update(data)
|
||||
.digest("base64url");
|
||||
}
|
||||
|
||||
const generate = () => {
|
||||
const sign = (header, payload) =>
|
||||
makeHmac(`${header}.${payload}`);
|
||||
|
||||
const getIPHash = (ip) =>
|
||||
makeHmac(ip).slice(0, 8);
|
||||
|
||||
const generate = (ip) => {
|
||||
const exp = Math.floor(new Date().getTime() / 1000) + env.jwtLifetime;
|
||||
|
||||
const header = toBase64URL(JSON.stringify({
|
||||
@ -21,10 +28,11 @@ const generate = () => {
|
||||
|
||||
const payload = toBase64URL(JSON.stringify({
|
||||
jti: nanoid(8),
|
||||
sub: getIPHash(ip),
|
||||
exp,
|
||||
}));
|
||||
|
||||
const signature = makeHmac(header, payload);
|
||||
const signature = sign(header, payload);
|
||||
|
||||
return {
|
||||
token: `${header}.${payload}.${signature}`,
|
||||
@ -32,7 +40,7 @@ const generate = () => {
|
||||
};
|
||||
}
|
||||
|
||||
const verify = (jwt) => {
|
||||
const verify = (jwt, ip) => {
|
||||
const [header, payload, signature] = jwt.split(".", 3);
|
||||
const timestamp = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
@ -40,17 +48,16 @@ const verify = (jwt) => {
|
||||
return false;
|
||||
}
|
||||
|
||||
const verifySignature = makeHmac(header, payload);
|
||||
const verifySignature = sign(header, payload);
|
||||
|
||||
if (verifySignature !== signature) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (timestamp >= JSON.parse(fromBase64URL(payload)).exp) {
|
||||
return false;
|
||||
}
|
||||
const data = JSON.parse(fromBase64URL(payload));
|
||||
|
||||
return true;
|
||||
return getIPHash(ip) === data.sub
|
||||
&& timestamp <= data.exp;
|
||||
}
|
||||
|
||||
export default {
|
||||
|
Reference in New Issue
Block a user