@bitblit/ratchet-warden-common
Version:
Typescript library to simplify using simplewebauthn and secondary auth methods over GraphQL
236 lines • 9.48 kB
JavaScript
import { WardenContactType } from "../model/warden-contact-type.js";
import { Logger } from "@bitblit/ratchet-common/logger/logger";
import { StringRatchet } from "@bitblit/ratchet-common/lang/string-ratchet";
import { WardenLoginRequestType } from "../model/warden-login-request-type.js";
import { BooleanRatchet } from "@bitblit/ratchet-common/lang/boolean-ratchet";
export class WardenUtils {
constructor() {
}
static extractContactsOfType(req, type) {
let rval = null;
if (req?.contactMethods) {
rval = req.contactMethods.filter((s) => s.type === type).map((s) => s.value);
}
return rval;
}
static loginRequestErrors(req) {
const rval = [];
if (req) {
if (req.type) {
switch (req.type) {
case WardenLoginRequestType.ExpiringToken:
if (!req.userId && !WardenUtils.validContact(req.contact)) {
rval.push('User ID or contact is required');
}
if (!req.expiringToken) {
rval.push('Expiring token is required');
}
break;
case WardenLoginRequestType.ThirdParty:
if (req.thirdPartyToken) {
if (!req.thirdPartyToken.thirdParty) {
rval.push('Third party is required');
}
if (!req.thirdPartyToken.token) {
rval.push('Third party token is required');
}
}
else {
rval.push('Third party auth is required');
}
break;
case WardenLoginRequestType.WebAuthn:
if (!req.userId && !WardenUtils.validContact(req.contact)) {
rval.push('User ID or contact is required');
}
if (!req.webAuthn) {
rval.push('Web authn is required');
}
break;
case WardenLoginRequestType.JwtTokenToRefresh:
if (!req.jwtTokenToRefresh) {
rval.push('JwtToken is required');
}
break;
default: rval.push('Unknown request type');
}
}
else {
rval.push('Request type is null');
}
}
else {
rval.push('Request is null');
}
return rval;
}
static validLoginRequest(req) {
return WardenUtils.loginRequestErrors(req).length === 0;
}
static stringToWardenContact(input) {
let rval = null;
const type = WardenUtils.stringToContactType(input);
if (type) {
rval = {
type: type,
value: input,
};
}
else {
Logger.error('Failed to convert a string to a contact type', input);
}
return rval;
}
static teamRolesToRoles(teamRoles) {
const rval = teamRoles?.length ? teamRoles.map((t) => WardenUtils.teamRoleToRoleString(t)) : [];
return rval;
}
static roleStringsToTeamRoles(roles) {
const rval = roles?.length ? roles.map((t) => WardenUtils.roleStringToTeamRole(t)) : [];
return rval;
}
static roleStringToTeamRole(role) {
let rval = null;
if (role && role.indexOf('_/_') >= 0) {
const sp = role.split('_/_');
rval = {
teamId: sp[0],
roleId: sp[1],
};
}
return rval;
}
static teamRoleToRoleString(tr) {
let rval = null;
if (tr?.roleId && tr?.teamId) {
rval = tr.teamId + '_/_' + tr.roleId;
}
return rval;
}
static stringToContactType(input) {
let rval = null;
if (StringRatchet.trimToNull(input)) {
rval = WardenUtils.stringIsEmailAddress(input) ? WardenContactType.EmailAddress : null;
rval = !rval && WardenUtils.stringIsPhoneNumber(input) ? WardenContactType.TextCapablePhoneNumber : rval;
}
return rval;
}
static validContact(contact) {
let rval = false;
if (contact?.type && StringRatchet.trimToNull(contact?.value)) {
switch (contact.type) {
case WardenContactType.EmailAddress:
rval = WardenUtils.stringIsEmailAddress(contact.value);
break;
case WardenContactType.TextCapablePhoneNumber:
rval = WardenUtils.stringIsPhoneNumber(contact.value);
break;
default:
rval = false;
}
}
return rval;
}
static stringIsEmailAddress(value) {
return !!value.match(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/);
}
static stringIsPhoneNumber(value) {
return !!value.match(/^[\\+]?[(]?[0-9]{3}[)]?[-\\s\\.]?[0-9]{3}[-\\s\\.]?[0-9]{4,6}$/im);
}
static stripWardenEntryToSummary(we) {
const rval = we
? {
userId: we.userId,
userLabel: we.userLabel,
contactMethods: we.contactMethods,
webAuthnAuthenticatorSummaries: (we?.webAuthnAuthenticators || []).map((s) => WardenUtils.stripWardenWebAuthnEntryToSummary(s)),
}
: null;
return rval;
}
static stripWardenWebAuthnEntryToSummary(we) {
const rval = we
? {
origin: we.origin,
applicationName: we.applicationName,
deviceLabel: we.deviceLabel,
credentialIdBase64: we.credentialIdBase64,
}
: null;
return rval;
}
static wrapperIsExpired(value) {
const rval = value?.userObject?.exp && value.expirationEpochSeconds < Date.now() / 1000;
return rval;
}
static userHasGlobalRole(user, roleId) {
return WardenUtils.userHasGlobalRoles(user, [roleId], true);
}
static userHasRoleOnTeam(user, teamId, roleId) {
return WardenUtils.userHasRolesOnTeam(user, teamId, [roleId], true);
}
static userHasAtLeastOneGlobalRole(user, roleIds) {
return WardenUtils.userHasGlobalRoles(user, roleIds, false);
}
static userHasAtLeastOneRoleOnTeam(user, teamId, roleIds) {
return WardenUtils.userHasRolesOnTeam(user, teamId, roleIds, false);
}
static userHasAllGlobalRoles(user, roleIds) {
return WardenUtils.userHasGlobalRoles(user, roleIds, true);
}
static userHasAllRolesOnTeam(user, teamId, roleIds) {
return WardenUtils.userHasRolesOnTeam(user, teamId, roleIds, true);
}
static userHasGlobalRoles(user, inRoleIds, combineWithAnd) {
let rval = false;
const roleIds = inRoleIds ? inRoleIds.map(r => StringRatchet.trimToNull(r)?.toLowerCase()) : null;
if (user && roleIds && roleIds.length > 0) {
const hasMap = user ? roleIds.map(r => !!user.globalRoleIds.find(gr => StringRatchet.trimToEmpty(gr).toLowerCase() === r)) : [false];
rval = combineWithAnd ? BooleanRatchet.allTrue(hasMap) : BooleanRatchet.anyTrue(hasMap);
}
return rval;
}
static userHasRolesOnTeam(user, inTeamId, inRoleIds, combineWithAnd) {
let rval = false;
const teamId = StringRatchet.trimToNull(inTeamId)?.toLowerCase();
const roleIds = inRoleIds ? inRoleIds.map(r => StringRatchet.trimToNull(r)?.toLowerCase()) : null;
if (user && teamId && roleIds && roleIds.length > 0) {
const hasMap = user ? roleIds.map(r => !!(user?.teamRoleMappings?.find(s => StringRatchet.trimToEmpty(s.teamId).toLowerCase() === teamId && StringRatchet.trimToEmpty(s.roleId).toLowerCase() === r))) : [false];
rval = combineWithAnd ? BooleanRatchet.allTrue(hasMap) : BooleanRatchet.anyTrue(hasMap);
}
return rval;
}
static userIsTeamMember(user, inTeamId) {
return WardenUtils.userHasAnyRoleOnTeam(user, inTeamId);
}
static userHasAnyRoleOnTeam(user, inTeamId) {
let rval = false;
const teamId = StringRatchet.trimToNull(inTeamId)?.toLowerCase();
if (user && teamId) {
rval = !!user.teamRoleMappings.find(s => StringRatchet.trimToNull(s.teamId).toLowerCase() === teamId);
}
return rval;
}
static usersTeamMemberships(user) {
let rval = [];
if (user) {
const s = new Set(user.teamRoleMappings.map(s => StringRatchet.trimToNull(s.teamId).toLowerCase()));
rval = Array.from(s);
}
return rval;
}
static wardenUserDecorationFromToken(jwt) {
let rval = null;
if (jwt) {
rval = {
userTokenData: jwt.user,
proxyUserTokenData: jwt.proxy,
userTokenExpirationSeconds: null,
globalRoleIds: jwt.globalRoleIds,
teamRoleMappings: jwt.teamRoleMappings
};
}
return rval;
}
}
//# sourceMappingURL=warden-utils.js.map