263 lines
5.8 KiB
TypeScript
263 lines
5.8 KiB
TypeScript
import { Arrays } from "../../browser/tools/Arrays";
|
|
import { CryptIO } from "../crypt/CryptIO";
|
|
import { Files } from "../files/Files";
|
|
import { Permission } from "./permissions/Permission";
|
|
import { Role } from "./permissions/Role";
|
|
import { Token } from "./Token";
|
|
import { TokenDB } from "./TokenDB";
|
|
import { UserData } from "./UserData";
|
|
import { UserManagementServer } from "./UserManagementServer";
|
|
|
|
export class SerializedUserDB
|
|
{
|
|
users:UserData[];
|
|
}
|
|
|
|
export class UserDB
|
|
{
|
|
_ums:UserManagementServer;
|
|
_path:string;
|
|
|
|
users:UserData[] = [];
|
|
_pendingUsers:UserData[] = [];
|
|
|
|
_signUpTokens = new Map<string,Token>();
|
|
_passwordChangeTokens = new Map<string,Token>();
|
|
|
|
|
|
|
|
|
|
async hasUserWithEmail( email:string ):Promise<boolean>
|
|
{
|
|
return this.users.findIndex( u => u.email === email ) != -1;
|
|
}
|
|
|
|
async hasUserWithID( id:string ):Promise<boolean>
|
|
{
|
|
return this.users.findIndex( u => u.id === id ) != -1;
|
|
}
|
|
|
|
async signUp( email:string, password:string, userName:string = "User" ):Promise<UserData>
|
|
{
|
|
let userData = this._pendingUsers.find( u => u.email === email );
|
|
|
|
if ( ! userData )
|
|
{
|
|
userData = new UserData();
|
|
userData.id = CryptIO.createUUID();
|
|
userData.email = email;
|
|
userData.hashedPassword = await CryptIO.hash( password );
|
|
userData.name = userName;
|
|
userData.role = Role.User;
|
|
userData.permissions = [];
|
|
|
|
this._pendingUsers.push( userData );
|
|
|
|
await this.save();
|
|
|
|
}
|
|
|
|
|
|
return Promise.resolve( userData );
|
|
}
|
|
|
|
async createSignUpConfirmation( userData:UserData, ip:string ):Promise<Token>
|
|
{
|
|
let token = await this._ums.tokenDB.create( ip );
|
|
|
|
this._signUpTokens.set( userData.id, token );
|
|
|
|
return Promise.resolve( token );
|
|
}
|
|
|
|
async createPasswordChange( userData:UserData, ip:string ):Promise<Token>
|
|
{
|
|
let token = await this._ums.tokenDB.create( ip );
|
|
|
|
this._passwordChangeTokens.set( userData.id, token );
|
|
|
|
return Promise.resolve( token );
|
|
}
|
|
|
|
async byID( id:string )
|
|
{
|
|
return this.users.find( u => u.id === id );
|
|
}
|
|
|
|
async byEmail( email:string )
|
|
{
|
|
return this.users.find( u => u.email === email );
|
|
}
|
|
|
|
async confirmUserSignUp( userID:string, tokenID:string, ip:string ):Promise<boolean>
|
|
{
|
|
let user = this._pendingUsers.find( u => u.id == userID );
|
|
|
|
if ( ! user )
|
|
{
|
|
return Promise.resolve( false );
|
|
}
|
|
|
|
if ( ! this._signUpTokens.has( userID ) )
|
|
{
|
|
return Promise.resolve( false );
|
|
}
|
|
|
|
let token = this._signUpTokens.get( userID );
|
|
|
|
if ( token.id != tokenID )
|
|
{
|
|
return Promise.resolve( false );
|
|
}
|
|
|
|
let isValid = await this._ums.tokenDB.validate( token, ip );
|
|
|
|
if ( isValid )
|
|
{
|
|
Arrays.remove( this._pendingUsers, user );
|
|
this._signUpTokens.delete( userID );
|
|
this._ums.tokenDB._tokens.delete( token.id );
|
|
this.users.push( user );
|
|
|
|
await this.save();
|
|
|
|
}
|
|
|
|
return Promise.resolve( isValid );
|
|
}
|
|
|
|
async changePassword( userID:string, tokenID:string, password:string, ip:string ):Promise<boolean>
|
|
{
|
|
if ( ! this._passwordChangeTokens.has( userID ) )
|
|
{
|
|
return Promise.resolve( false );
|
|
}
|
|
|
|
let token = this._passwordChangeTokens.get( userID );
|
|
|
|
if ( token.id != tokenID )
|
|
{
|
|
return Promise.resolve( false );
|
|
}
|
|
|
|
let isValid = await this._ums.tokenDB.validate( token, ip );
|
|
|
|
if ( isValid )
|
|
{
|
|
this._passwordChangeTokens.delete( userID );
|
|
this._ums.tokenDB._tokens.delete( token.id );
|
|
let userData = await this._ums.userDB.byID( userID );
|
|
userData.hashedPassword = await CryptIO.hash( password );
|
|
|
|
await this.save();
|
|
|
|
}
|
|
|
|
return Promise.resolve( isValid );
|
|
}
|
|
|
|
|
|
async login( email:string, password:string, ip:string ):Promise<Token>
|
|
{
|
|
let user = await this.byEmail( email );
|
|
|
|
if ( ! user )
|
|
{
|
|
return Promise.resolve( null );
|
|
}
|
|
|
|
let passwordValid = await CryptIO.verifyHash( password, user.hashedPassword );
|
|
|
|
if ( ! passwordValid )
|
|
{
|
|
return Promise.resolve( null );
|
|
}
|
|
|
|
let hour = 60;
|
|
let day = hour * 24;
|
|
let week = day * 7;
|
|
|
|
let token = await this._ums.tokenDB.create( ip, week );
|
|
|
|
return Promise.resolve( token );
|
|
}
|
|
|
|
async hasPermission( ud:UserData, permissionID:string )
|
|
{
|
|
let hasOwnPermission = await this._hasPermission( permissionID, ud.permissions );
|
|
|
|
if ( hasOwnPermission )
|
|
{
|
|
return Promise.resolve( true );
|
|
}
|
|
|
|
let roleID = ud.role;
|
|
|
|
while ( roleID )
|
|
{
|
|
let role = this._ums._roles.get( roleID );
|
|
|
|
if ( ! role )
|
|
{
|
|
return Promise.resolve( false );
|
|
}
|
|
|
|
let hasRolePermission = await this._hasPermission( permissionID, role.permissions );
|
|
|
|
if ( hasRolePermission )
|
|
{
|
|
return Promise.resolve( true );
|
|
}
|
|
|
|
roleID = role.inherits;
|
|
}
|
|
|
|
return Promise.resolve( false );
|
|
}
|
|
|
|
protected async _hasPermission( permissionID:string, permissions:Permission[] ):Promise<boolean>
|
|
{
|
|
permissions = permissions || [];
|
|
|
|
for ( let p of permissions )
|
|
{
|
|
if ( Permission.isMatching( permissionID, p ) )
|
|
{
|
|
return Promise.resolve( true );
|
|
}
|
|
}
|
|
|
|
return Promise.resolve( false );
|
|
}
|
|
|
|
async save()
|
|
{
|
|
let serializedDB = new SerializedUserDB();
|
|
serializedDB.users = this.users;
|
|
|
|
await Files.saveJSON( this._path, serializedDB );
|
|
|
|
return Promise.resolve();
|
|
}
|
|
|
|
static async load( ums:UserManagementServer, path:string ):Promise<UserDB>
|
|
{
|
|
let userDB = new UserDB();
|
|
userDB._ums = ums;
|
|
userDB._path = path;
|
|
|
|
let userDBExists = await Files.exists( userDB._path );
|
|
|
|
if ( userDBExists )
|
|
{
|
|
let data = await Files.loadJSON<SerializedUserDB>( userDB._path );
|
|
userDB.users = data.users;
|
|
}
|
|
|
|
|
|
return Promise.resolve( userDB );
|
|
}
|
|
|
|
|
|
|
|
} |