@perfood/couch-auth
Version:
Easy and secure authentication for CouchDB/Cloudant. Based on SuperLogin, updated and rewritten in Typescript.
191 lines (190 loc) • 6.51 kB
TypeScript
import { Request } from 'express';
import { Document, IdentifiedDocument, MaybeRevisionedDocument } from 'nano';
export interface IdentifiedObj {
name: string;
type: string;
}
export type SessionCleanupType = 'all' | 'expired' | 'other';
export type CreateSessionOpts = {
/** the email, username or UUID (depending on your config) */
login: string;
/** 'local' or one of the configured OAuth providers */
provider: string;
/** if `true`, interpret `login` always as UUID */
byUUID?: boolean;
/**
* see `security` -> `sessionConfig`. Custom session lifetime depending on the
* user's roles and the config entry for this session type.
*/
sessionType?: string;
};
/** copied from https://nodemailer.com/smtp/pooled/ because it's not included in the typings */
export interface PooledSMTPOptions {
/** set to true to use pooled connections (defaults to false) instead of creating a new connection for every email */
pool?: boolean;
/** is the count of maximum simultaneous connections to make against the SMTP server (defaults to 5) */
maxConnections?: number;
/** limits the message count to be sent using a single connection (defaults to 100). After maxMessages is reached the connection is dropped and a new one is created for the following messages */
maxMessages?: number;
}
export interface CouchDbAuthDoc extends IdentifiedDocument, MaybeRevisionedDocument, IdentifiedObj {
user_uid: string;
user_id: string;
password?: string;
expires: number;
roles: string[];
provider: string;
password_scheme?: string;
iterations?: number;
derived_key?: string;
salt?: string;
}
export interface HashResult {
salt?: string;
derived_key?: string;
/**
* timestamp of the creation of this HashResult. If `undefined`, the default
* iteration number (10) is used, else the value specified in the config
* (`security.iterations`) that matches the creation date.
*/
created?: number;
}
export interface LocalHashObj extends HashResult {
failedLoginAttempts?: number;
iterations?: number;
lockedUntil?: number;
}
export interface SignUpObj {
provider: string;
timestamp: string;
}
export interface RegistrationForm {
email: string;
username?: string;
password: string;
confirmPassword: string;
name?: string;
[x: string]: any;
}
export interface PersonalDBCollection {
[dbName: string]: IdentifiedObj;
}
export interface TimeRestricted {
issued: number;
expires: number;
}
export interface SessionObj extends TimeRestricted {
provider: string;
sessionType?: string;
}
export interface SessionCollection {
[session: string]: SessionObj;
}
/** actions performed by the user and logged via `activityLog` */
export type UserAction = 'email-verified' | 'signup' | 'create-social' | 'link-social' | 'login' | 'password-reset' | 'password-change' | 'forgot-password' | 'email-changed' | 'logout' | 'logout-others' | 'logout-all' | 'refresh' | 'consents';
/** possible events that are emmitted */
export type UserEvent = UserAction | 'signup-attempt' | 'forgot-password-attempt' | 'forgot-username-attempt' | 'email-change-attempt' | 'user-db-added' | 'user-deleted' | 'confirmation-email-error';
export interface UserActivity {
timestamp: string;
action: UserAction;
/**
* Depending on the action, this is either the OAuth-provider, `'local'` or
* the current session-ID
*/
provider: string;
}
export interface PasswortResetEntry extends TimeRestricted {
token: string;
}
export interface SlUserDoc extends Document, IdentifiedObj {
user_uid?: string;
/** this is the `_id` in version 1 of superlogin - for login with username */
key: string;
roles: string[];
providers: string[];
local: LocalHashObj;
activity?: UserActivity[];
forgotPassword?: PasswortResetEntry;
unverifiedEmail?: {
email: string;
token: string;
};
/**
* After an `unverifiedEmail` was confirmed, the used token is documented
* until a new email change token is requested.
*/
lastEmailToken?: string;
signUp: SignUpObj;
personalDBs: PersonalDBCollection;
email: string;
session: SessionCollection;
/** from Version 0.17.0 onwards, expired session keys are reused */
inactiveSessions: string[];
profile: any;
consents?: Record<string, ConsentSlEntry[]>;
}
export interface ConsentConfig {
minVersion: number;
currentVersion: number;
required: boolean;
}
export interface ConsentRequest {
accepted: boolean;
version: number;
}
export interface ConsentSlEntry extends ConsentRequest {
timestamp: string;
}
export interface SlUserNew extends SlUserDoc {
password?: string;
confirmPassword?: string;
}
export interface SlRefreshSession extends TimeRestricted {
provider: string;
roles: string[];
token: string;
/** This will still be the old `_id`, i.e. `key` now */
user_id: string;
/** unique identifier of the user's DB, `including` the hyphens. */
user_uid: string;
/**
* If `config.security.sessionConfig` is used, this stores the type of session
* that was issued when logging in. Necessary to select the correct lifetime
* when extending the session.
*/
sessionType?: string;
}
export interface SlLoginSession extends SlRefreshSession {
password: string;
userDBs: {
[db: string]: string;
};
profile?: string;
/** Name for Display purposes only */
name?: string;
}
export interface SlRequestUser {
/** `"local"` or the OAuth provider */
provider?: string;
/** UUID (without hyphens) of the user */
_id?: string;
/**
* In this context, this is the current _session_ of the user, not the `key`
* in the SlUserDoc!
*/
key?: string;
roles?: string[];
/** @deprecated Also the UUID (without hyphens) - does this make any sense? */
user_id?: string;
/** If set up via `local.consents` in the config, the consents need to passed for registration. */
consents?: Record<string, ConsentRequest>;
/**
* If set up via `security.sessionConfig`, a custom session type can be
* requested during `login`, `register`, and `password-reset`.
*/
sessionType?: string;
}
export interface SlRequest extends Request {
user: SlRequestUser;
}
export type SlAction = (a: SlUserDoc, b: string) => Promise<SlUserDoc>;