Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions db/migrations/001_init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@
-- sessions
-- Cookie-backed session rows. Also hashed at rest.
--
-- user_totp, mfa_challenges
-- Optional TOTP second factor. Shared secrets are encrypted with the
-- server pepper before storage; recovery codes and login challenge
-- tokens are hashed at rest.
--
-- vaults
-- 1:1 with users, created lazily on first PUT. No salt_v here — that
-- lives on the user row (see above).
Expand Down Expand Up @@ -141,6 +146,27 @@ CREATE TABLE sessions (
CREATE INDEX idx_sessions_user ON sessions(user_id);
CREATE INDEX idx_sessions_expires ON sessions(expires_at);

CREATE TABLE user_totp (
user_id INTEGER PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
secret_enc TEXT,
pending_secret_enc TEXT,
recovery_hashes TEXT NOT NULL DEFAULT '[]',
enabled INTEGER NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);

CREATE TABLE mfa_challenges (
token_hash TEXT PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
expires_at INTEGER NOT NULL,
attempts INTEGER NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL
);

CREATE INDEX idx_mfa_challenges_user ON mfa_challenges(user_id);
CREATE INDEX idx_mfa_challenges_expires ON mfa_challenges(expires_at);

CREATE TABLE vaults (
user_id INTEGER PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
blob TEXT NOT NULL,
Expand Down
5 changes: 5 additions & 0 deletions lib/appFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const { createVerificationsRepo } = require('./verifications');
const {
createPendingRegistrationsRepo,
} = require('./pendingRegistrations');
const { createTotpRepo } = require('./totp');
const { createVaultsRepo } = require('./vaults');
const { createVoteReceiptsRepo } = require('./voteReceipts');
const { createProposalDraftsRepo } = require('./proposalDrafts');
Expand Down Expand Up @@ -97,6 +98,7 @@ function buildServices({
return {
users: createUsersRepo(db, { now }),
sessions: createSessionStore(db, { now }),
totp: createTotpRepo(db, { now }),
verifications: createVerificationsRepo(db, { now }),
pendingRegistrations: createPendingRegistrationsRepo(db, { now }),
vaults: createVaultsRepo(db, { now }),
Expand Down Expand Up @@ -175,13 +177,15 @@ function mountAuthAndVault(
const limiters = disableRateLimit
? {
login: rateLimiters.disabled(),
mfaLogin: rateLimiters.disabled(),
register: rateLimiters.disabled(),
verifyEmail: rateLimiters.disabled(),
vote: rateLimiters.disabled(),
reconcile: rateLimiters.disabled(),
}
: {
login: rateLimiters.loginLimiter(),
mfaLogin: rateLimiters.mfaLoginLimiter(),
register: rateLimiters.registerLimiter(),
verifyEmail: rateLimiters.verifyEmailLimiter(),
vote: rateLimiters.voteLimiter(),
Expand All @@ -193,6 +197,7 @@ function mountAuthAndVault(
createAuthRouter({
users: services.users,
sessions: services.sessions,
totp: services.totp,
pendingRegistrations: services.pendingRegistrations,
vaults: services.vaults,
mailer,
Expand Down
18 changes: 18 additions & 0 deletions lib/kdf.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,22 @@ function assertPepperConfigured() {
loadPepper();
}

function hmacServerSecret(value, context = 'default') {
return crypto
.createHmac('sha256', loadPepper())
.update(String(context), 'utf8')
.update('\0')
.update(String(value), 'utf8')
.digest('hex');
}

function deriveServerKey(context = 'default') {
return crypto
.createHmac('sha256', loadPepper())
.update(`sysnode:${context}`, 'utf8')
.digest();
}

function constantTimeEqualHex(a, b) {
if (typeof a !== 'string' || typeof b !== 'string') return false;
const aLower = a.toLowerCase();
Expand All @@ -140,6 +156,8 @@ module.exports = {
generateSalt,
hashAuthHash,
verifyAuthHash,
hmacServerSecret,
deriveServerKey,
constantTimeEqualHex,
assertPepperConfigured,
KdfConfigError,
Expand Down
Loading
Loading