import { Nymph, EntityInterface, FormattedSelector, Options, TilmeldInterface, TilmeldAccessLevels, ACProperties } from '@nymphjs/nymph'; import { Request, Response } from 'express'; import { Config } from './conf/index.js'; import Group from './Group.js'; import User, { UserData } from './User.js'; /** * A user and group system for Nymph.js. * * Written by Hunter Perrin for SciActive. * * @author Hunter Perrin * @copyright SciActive Inc * @see http://nymph.io/ */ export default class Tilmeld implements TilmeldInterface { /** * The Nymph instance. */ nymph: Nymph; /** * The Tilmeld config. */ config: Config; /** * The currently logged in user. */ currentUser: (User & UserData) | null; /** * The user class for this instance of Tilmeld. */ User: typeof User; /** * The group class for this instance of Tilmeld. */ Group: typeof Group; /** * If you will be performing authentication functions (logging in/out), you * should set these so Tilmeld can read and write cookies and headers. * * If you want the user to be authenticated with the cookie and/or header they * provide, you should set at least the request. It's better to set both, so * the JWT can be updated if needed. * * After you set these, call `authenticate()` to read user authentication data * from them and fill the user's session. * * If you want to support cookie based authentication (which still requires an * XSRF token for security), you should enable the cookie parser middleware. */ request: Request | null; response: Response | null; /** * Used to avoid infinite loop. */ private alreadyLoggedOutSwitch; /** * Gatekeeper ability cache. * * Gatekeeper will cache the user's abilities that it calculates, so it can * check faster if that user has been checked before. */ private gatekeeperCache; /** * Create a new instance of Tilmeld. * * @param config The Tilmeld configuration. */ constructor(config: Partial & { jwtSecret: string; }); /** * This is used internally by Nymph. Don't call it yourself. * * @returns A clone of this instance. */ clone(): Tilmeld; /** * Initialize Tilmeld. * * This is meant to be called internally by Nymph. Don't call this directly. * * @param nymph The Nymph instance. */ init(nymph: Nymph): void; /** * Check to see if the current user has an ability. * * If `ability` is undefined, it will check to see if a user is currently * logged in. * * @param ability The ability. * @returns Whether the user has the given ability. */ gatekeeper(ability?: string): boolean; private initAccessControl; /** * Add selectors to a list of options and selectors which will limit results * to only entities the current user has access to. * * @param optionsAndSelectors The options and selectors of the query. */ addAccessControlSelectors(options: Options, selectors: FormattedSelector[]): void; /** * Check an entity's permissions for a user. * * This will check the AC (Access Control) properties of the entity. These * include the following properties: * * - acUser * - acGroup * - acOther * - acRead * - acWrite * - acFull * * "acUser" refers to the entity's owner, "acGroup" refers to all users in the * entity's group and all ancestor groups, and "acOther" refers to any user * who doesn't fit these descriptions. * * Each of these properties should be either NO_ACCESS, READ_ACCESS, * WRITE_ACCESS, or FULL_ACCESS. * * - NO_ACCESS - the user has no access to the entity. * - READ_ACCESS, the user has read access to the entity. * - WRITE_ACCESS, the user has read and write access to the entity, but can't * delete it, change its access controls, or change its ownership. * - FULL_ACCESS, the user has read, write, and delete access to the entity, * as well as being able to manage its access controls and ownership. * * These properties default to: * * - acUser = TilmeldAccessLevels.FULL_ACCESS * - acGroup = TilmeldAccessLevels.READ_ACCESS * - acOther = TilmeldAccessLevels.NO_ACCESS * * "acRead", "acWrite", and "acFull" are arrays of users and/or groups that * also have those permissions. * * Only users with FULL_ACCESS have the ability to change any of the ac*, * user, and group properties. * * The following conditions will result in different checks, which determine * whether the check passes: * * - It is a user or group. (True for READ_ACCESS or Tilmeld admins.) * - It is a user or group that belongs to a domain the current user is an * admin for, and domain support is enabled. (Always true.) * - No user is logged in. (Check other AC.) * - The entity is the user. (Always true.) * - It is the user's primary group. (True for READ_ACCESS.) * - The user or its groups are listed in "acRead". (True for READ_ACCESS.) * - The user or its groups are listed in "acWrite". (True for READ_ACCESS and * WRITE_ACCESS.) * - The user or its groups are listed in "acFull". (Always true.) * - Its "user" is the user. (It is owned by the user.) (Check user AC.) * - Its "group" is the user's primary group. (Check group AC.) * - Its "group" is one of the user's secondary groups. (Check group AC.) * - Its "group" is a descendant of one of the user's groups. (Check group * AC.) * - None of the above. (Check other AC.) * * @param entity The entity to check. * @param type The lowest level of permission to consider a pass. * @param user The user to check permissions for. If null, uses the current user. If false, checks for public access. * @param acProperties The acProperties to use instead of getting them from the entity. * @returns Whether the current user has at least `type` permission for the entity. */ checkPermissions(entity: EntityInterface, type?: TilmeldAccessLevels, user?: (User & UserData) | false, acProperties?: ACProperties): boolean; /** * Check a UID's permissions for a user. * * ## THIS ONLY CHECKS AUTOMATICALLY FOR CLIENT REQUESTS. * * UID functions on the Node.js side are not checked automatically. This * function is only run automatically for UID functions run from the client. * You should call this function manually if you're running a UID function on * the Node.js side and you want it gated. * * This will check the Tilmeld config and the user's abilities. * * - READ_ACCESS, the UID is listed in clientReadableUIDs or the user has the * "uid/get/nameofuid" ability. * - WRITE_ACCESS, the UID is listed in clientEnabledUIDs or the user has the * "uid/new/nameofuid" ability. * - FULL_ACCESS, the UID is listed in clientSetabledUIDs or the user has the * "uid/set/nameofuid" ability. * * @param name The UID to check. * @param type The lowest level of permission to consider a pass. * @param user The user to check permissions for. If null, uses the current user. If false, checks for public access. * @returns Whether the current user has at least `type` permission for the UID. */ checkClientUIDPermissions(name: string, type?: TilmeldAccessLevels, user?: (User & UserData) | false): Promise; /** * Fill session user data. * * @param user The user. */ fillSession(user: User & UserData): Promise; /** * Clear session user data. */ clearSession(): void; /** * Validate and extract the user from a token. * * @param token The authentication token. * @returns The user on success, null on failure. */ extractToken(token: string): Promise<(User & UserData) | null>; /** * Check for TILMELDAUTH and TILMELDSWITCH tokens, and, if set, authenticate * from it/them. * * You can also call this function after setting `response.locals.user` to the * user you want to authenticate. You *should* check for `user.enabled` before * setting this variable, unless you explicitly want to log in as a disabled * user. (The user must be an instance of the User class for this Tilmeld * instance.) * * This function will set `response.locals.user` to the logged in user on * successful authentication. * * @param skipXsrfToken Skip the XSRF token check. * @param skipRenew Skip the token renewal step, even if the token is close to expiration. * @returns True if a user was authenticated, false on any failure. */ authenticate(skipXsrfToken?: boolean, skipRenew?: boolean): Promise; /** * Logs the given user into the system. * * @param user The user. * @param sendAuthHeader Send the auth token as a custom header. * @param sendCookie Send the auth token as a cookie. * @returns True on success, false on failure. */ login(user: User & UserData, sendAuthHeader: boolean, sendCookie?: boolean): Promise; /** * Adds a switch auth token for the given user. * * This effectively logs the current user in to the system as the given user. * * @param user The user. * @param sendAuthHeader Send the auth token as a custom header. * @param sendCookie Send the auth token as a cookie. * @returns True on success, false on failure. */ loginSwitch(user: User & UserData, sendAuthHeader: boolean, sendCookie?: boolean): Promise; /** * Logs the current user out of the system. * * @param clearCookie Clear the auth cookie. (Also send a header.) */ logout(clearCookie?: boolean): Promise; /** * Clears the switch user out of the system. * * @param clearCookie Clear the auth cookie. (Also send a header.) */ logoutSwitch(clearCookie?: boolean): Promise; }