mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 04:37:11 +01:00
Switch to json web tokens.
This commit is contained in:
parent
5219582803
commit
cb0c912c5b
10 changed files with 202 additions and 86 deletions
|
|
@ -1,31 +1,38 @@
|
|||
import crypto from 'crypto';
|
||||
import { v5 as uuid, v4 } from 'uuid';
|
||||
import Cryptr from 'cryptr';
|
||||
import { v5 } from 'uuid';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import bcrypt from 'bcrypt';
|
||||
|
||||
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
||||
|
||||
const cryptr = new Cryptr(hash(process.env.HASH_SALT, process.env.DATABASE_URL));
|
||||
|
||||
export function md5(s) {
|
||||
return crypto.createHash('md5').update(s).digest('hex');
|
||||
export function sha256(...args) {
|
||||
return crypto.createHash('sha256').update(args.join('')).digest('hex');
|
||||
}
|
||||
|
||||
export function hash(...args) {
|
||||
return uuid(args.join(''), md5(process.env.HASH_SALT));
|
||||
export function secret() {
|
||||
return sha256(process.env.HASH_SALT);
|
||||
}
|
||||
|
||||
export function validHash(s) {
|
||||
export function uuid(...args) {
|
||||
return v5(args.join(''), v5(process.env.HASH_SALT, v5.DNS));
|
||||
}
|
||||
|
||||
export function random(n = 64) {
|
||||
return crypto.randomBytes(n).toString('hex');
|
||||
}
|
||||
|
||||
export function isValidHash(s) {
|
||||
return UUID_REGEX.test(s);
|
||||
}
|
||||
|
||||
export function encrypt(s) {
|
||||
return cryptr.encrypt(s);
|
||||
export async function createToken(payload, options) {
|
||||
return jwt.sign(payload, secret(), options);
|
||||
}
|
||||
|
||||
export function decrypt(s) {
|
||||
return cryptr.decrypt(s);
|
||||
export async function parseToken(token, options) {
|
||||
return jwt.verify(token, secret(), options);
|
||||
}
|
||||
|
||||
export function random() {
|
||||
return v4();
|
||||
export function checkPassword(password, hash) {
|
||||
return bcrypt.compare(password, hash);
|
||||
}
|
||||
|
|
|
|||
10
lib/db.js
10
lib/db.js
|
|
@ -95,3 +95,13 @@ export async function saveEvent(website_id, session_id, url, event_type, event_v
|
|||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function getAccount(username = '') {
|
||||
return runQuery(
|
||||
prisma.account.findOne({
|
||||
where: {
|
||||
username,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,50 +1,52 @@
|
|||
import { getWebsite, getSession, createSession } from 'lib/db';
|
||||
import { getCountry, getDevice, getIpAddress, isValidSession } from 'lib/utils';
|
||||
import { hash } from 'lib/crypto';
|
||||
import { getCountry, getDevice, getIpAddress } from 'lib/utils';
|
||||
import { uuid, parseToken, isValidHash } from 'lib/crypto';
|
||||
|
||||
export default async req => {
|
||||
const { payload } = req.body;
|
||||
const { session } = payload;
|
||||
const { website: website_uuid, hostname, screen, language, session } = payload;
|
||||
|
||||
if (isValidSession(session)) {
|
||||
return session;
|
||||
if (!isValidHash(website_uuid)) {
|
||||
throw new Error(`Invalid website: ${website_uuid}`);
|
||||
}
|
||||
|
||||
const ip = getIpAddress(req);
|
||||
const { userAgent, browser, os } = getDevice(req);
|
||||
const country = await getCountry(req, ip);
|
||||
const { website: website_uuid, hostname, screen, language } = payload;
|
||||
try {
|
||||
return await parseToken(session);
|
||||
} catch {
|
||||
const ip = getIpAddress(req);
|
||||
const { userAgent, browser, os } = getDevice(req);
|
||||
const country = await getCountry(req, ip);
|
||||
|
||||
if (website_uuid) {
|
||||
const website = await getWebsite(website_uuid);
|
||||
if (website_uuid) {
|
||||
const website = await getWebsite(website_uuid);
|
||||
|
||||
if (website) {
|
||||
const { website_id } = website;
|
||||
const session_uuid = hash(website_id, hostname, ip, userAgent, os);
|
||||
if (website) {
|
||||
const { website_id } = website;
|
||||
const session_uuid = uuid(website_id, hostname, ip, userAgent, os);
|
||||
|
||||
let session = await getSession(session_uuid);
|
||||
let session = await getSession(session_uuid);
|
||||
|
||||
if (!session) {
|
||||
session = await createSession(website_id, {
|
||||
if (!session) {
|
||||
session = await createSession(website_id, {
|
||||
session_uuid,
|
||||
hostname,
|
||||
browser,
|
||||
os,
|
||||
screen,
|
||||
language,
|
||||
country,
|
||||
});
|
||||
}
|
||||
|
||||
const { session_id } = session;
|
||||
|
||||
return {
|
||||
website_id,
|
||||
website_uuid,
|
||||
session_id,
|
||||
session_uuid,
|
||||
hostname,
|
||||
browser,
|
||||
os,
|
||||
screen,
|
||||
language,
|
||||
country,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
const { session_id } = session;
|
||||
|
||||
return [
|
||||
website_id,
|
||||
website_uuid,
|
||||
session_id,
|
||||
session_uuid,
|
||||
hash(website_id, website_uuid, session_id, session_uuid),
|
||||
].join(':');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
20
lib/utils.js
20
lib/utils.js
|
|
@ -1,9 +1,8 @@
|
|||
import requestIp from 'request-ip';
|
||||
import { browserName, detectOS } from 'detect-browser';
|
||||
import isLocalhost from 'is-localhost-ip';
|
||||
import maxmind from 'maxmind';
|
||||
import geolite2 from 'geolite2-redist';
|
||||
import isLocalhost from 'is-localhost-ip';
|
||||
import { hash } from './crypto';
|
||||
|
||||
export function getIpAddress(req) {
|
||||
// Cloudflare
|
||||
|
|
@ -44,20 +43,3 @@ export async function getCountry(req, ip) {
|
|||
|
||||
return result.country.iso_code;
|
||||
}
|
||||
|
||||
export function parseSession(session) {
|
||||
const [website_id, website_uuid, session_id, session_uuid, sig] = (session || '').split(':');
|
||||
return {
|
||||
website_id: parseInt(website_id),
|
||||
website_uuid,
|
||||
session_id: parseInt(session_id),
|
||||
session_uuid,
|
||||
sig,
|
||||
};
|
||||
}
|
||||
|
||||
export function isValidSession(session) {
|
||||
const { website_id, website_uuid, session_id, session_uuid, sig } = parseSession(session);
|
||||
|
||||
return hash(website_id, website_uuid, session_id, session_uuid) === sig;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue