143 lines
4.2 KiB
TypeScript
143 lines
4.2 KiB
TypeScript
|
import {Injectable} from '@angular/core';
|
||
|
import {CryptoService} from './crypto.service';
|
||
|
import {GlobalVarsService} from './global-vars.service';
|
||
|
import {AccessLevel, Network, PrivateUserInfo, PublicUserInfo} from '../types/identity';
|
||
|
import HDKey from 'hdkey';
|
||
|
|
||
|
@Injectable({
|
||
|
providedIn: 'root'
|
||
|
})
|
||
|
export class AccountService {
|
||
|
private static usersStorageKey = 'users';
|
||
|
private static levelsStorageKey = 'levels';
|
||
|
|
||
|
private static publicKeyRegex = /^[a-zA-Z0-9]{54,55}$/;
|
||
|
|
||
|
constructor(
|
||
|
private cryptoService: CryptoService,
|
||
|
private globalVars: GlobalVarsService,
|
||
|
) { }
|
||
|
|
||
|
// Public Getters
|
||
|
|
||
|
getPublicKeys(): any {
|
||
|
return Object.keys(this.getPrivateUsers());
|
||
|
}
|
||
|
|
||
|
getEncryptedUsers(): {[key: string]: PublicUserInfo} {
|
||
|
const hostname = this.globalVars.hostname;
|
||
|
const privateUsers = this.getPrivateUsers();
|
||
|
const publicUsers: {[key: string]: PublicUserInfo} = {};
|
||
|
|
||
|
for (const publicKey of Object.keys(privateUsers)) {
|
||
|
const privateUser = privateUsers[publicKey];
|
||
|
const accessLevel = this.getAccessLevel(publicKey, hostname);
|
||
|
if (accessLevel === AccessLevel.None) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
const encryptedSeedHex = this.cryptoService.encryptSeedHex(privateUser.seedHex, hostname);
|
||
|
const accessLevelHmac = this.cryptoService.accessLevelHmac(accessLevel, privateUser.seedHex);
|
||
|
|
||
|
publicUsers[publicKey] = {
|
||
|
hasExtraText: privateUser.extraText?.length > 0,
|
||
|
encryptedSeedHex,
|
||
|
network: privateUser.network,
|
||
|
accessLevel,
|
||
|
accessLevelHmac,
|
||
|
};
|
||
|
}
|
||
|
|
||
|
return publicUsers;
|
||
|
}
|
||
|
|
||
|
getAccessLevel(publicKey: string, hostname: string): AccessLevel {
|
||
|
const levels = JSON.parse(localStorage.getItem(AccountService.levelsStorageKey) || '{}');
|
||
|
const hostMapping = levels[hostname] || {};
|
||
|
const accessLevel = hostMapping[publicKey];
|
||
|
|
||
|
if (Object.values(AccessLevel).includes(accessLevel)) {
|
||
|
return accessLevel;
|
||
|
} else {
|
||
|
return AccessLevel.None;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Public Modifiers
|
||
|
|
||
|
addUser(keychain: HDKey, mnemonic: string, extraText: string, network: Network): string {
|
||
|
const seedHex = this.cryptoService.keychainToSeedHex(keychain);
|
||
|
|
||
|
return this.addPrivateUser({
|
||
|
seedHex,
|
||
|
mnemonic,
|
||
|
extraText,
|
||
|
network,
|
||
|
});
|
||
|
}
|
||
|
|
||
|
deleteUser(publicKey: string): void {
|
||
|
const privateUsers = this.getPrivateUsersRaw();
|
||
|
|
||
|
delete privateUsers[publicKey];
|
||
|
|
||
|
this.setPrivateUsersRaw(privateUsers);
|
||
|
}
|
||
|
|
||
|
setAccessLevel(publicKey: string, hostname: string, accessLevel: AccessLevel): void {
|
||
|
const levels = JSON.parse(localStorage.getItem(AccountService.levelsStorageKey) || '{}');
|
||
|
|
||
|
levels[hostname] ||= {};
|
||
|
levels[hostname][publicKey] = accessLevel;
|
||
|
|
||
|
localStorage.setItem(AccountService.levelsStorageKey, JSON.stringify(levels));
|
||
|
}
|
||
|
|
||
|
// Private Getters and Modifiers
|
||
|
|
||
|
// TEMP: public for import flow
|
||
|
public addPrivateUser(userInfo: PrivateUserInfo): string {
|
||
|
const privateUsers = this.getPrivateUsersRaw();
|
||
|
const privateKey = this.cryptoService.seedHexToPrivateKey(userInfo.seedHex);
|
||
|
const publicKey = this.cryptoService.privateKeyToDeSoPublicKey(privateKey, userInfo.network);
|
||
|
|
||
|
privateUsers[publicKey] = userInfo;
|
||
|
|
||
|
this.setPrivateUsersRaw(privateUsers);
|
||
|
|
||
|
return publicKey;
|
||
|
}
|
||
|
|
||
|
private getPrivateUsers(): {[key: string]: PrivateUserInfo} {
|
||
|
const privateUsers = this.getPrivateUsersRaw();
|
||
|
const filteredPrivateUsers: {[key: string]: PrivateUserInfo} = {};
|
||
|
|
||
|
for (const publicKey of Object.keys(privateUsers)) {
|
||
|
const privateUser = privateUsers[publicKey];
|
||
|
|
||
|
// Only include users from the current network
|
||
|
if (privateUser.network !== this.globalVars.network) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Get rid of some users who have invalid public keys
|
||
|
if (!publicKey.match(AccountService.publicKeyRegex)) {
|
||
|
this.deleteUser(publicKey);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
filteredPrivateUsers[publicKey] = privateUser;
|
||
|
}
|
||
|
|
||
|
return filteredPrivateUsers;
|
||
|
}
|
||
|
|
||
|
private getPrivateUsersRaw(): {[key: string]: PrivateUserInfo} {
|
||
|
return JSON.parse(localStorage.getItem(AccountService.usersStorageKey) || '{}');
|
||
|
}
|
||
|
|
||
|
private setPrivateUsersRaw(privateUsers: {[key: string]: PrivateUserInfo}): void {
|
||
|
localStorage.setItem(AccountService.usersStorageKey, JSON.stringify(privateUsers));
|
||
|
}
|
||
|
}
|