'use strict' ; import { Request } from 'express' ; import { Accounts } from '@Entities/Accounts' ; import { AccountEntity } from '@Entities/AccountEntity' ; import { Domains } from '@Entities/Domains' ; import { DomainEntity } from '@Entities/DomainEntity' ; import { Places } from '@Entities/Places' ; import { PlaceEntity } from '@Entities/PlaceEntity' ; import { GenericFilter } from '@Entities/EntityFilters/GenericFilter' ; import { createPublicKey } from 'crypto' ; import { VKeyedCollection , VKeyValue } from '@Tools/vTypes' ; import { IsNotNullOrEmpty , IsNullOrEmpty } from '@Tools/Misc' ; import { Logger } from '@Tools/Logging' ; import { Maturity } from '@Entities/Sets/Maturity' ; import { Visibility } from '@Entities/Sets/Visibility' ; export function convertBinKeyToPEM ( pBinKey ) { const publicKey = createPublicKey ( { key : pBinKey , format : 'der' , type : 'pkcs1' } ) ; const convertedKey = publicKey . export ( { type : 'spki' , format : 'pem' } ) ; return convertedKey as string ; } ; export function createSimplifiedPublicKey ( pPubKey ) { let keyLines = [ ] ; if ( pPubKey ) { keyLines = pPubKey . split ( '\n' ) ; keyLines . shift ( ) ; while ( keyLines . length > 1 && ( keyLines [ keyLines . length - 1 ] . length < 1 || keyLines [ keyLines . length - 1 ] . includes ( 'END PUBLIC KEY' ) ) ) { keyLines . pop ( ) ; } ; } return keyLines . join ( '' ) ; } ; export async function updateLocationInfo ( pReq ) { let newLoc = { } ; if ( pReq . vAuthAccount && pReq . body . location ) { try { const loc = pReq . body . location ; for ( const field of [ 'connected' , 'path' , 'place_id' , 'domain_id' , 'network_address' , 'node_id' , 'availability' ] ) { if ( loc . hasOwnProperty ( field ) ) { await Accounts . setField ( pReq . vAuthToken , pReq . vAuthAccount , field , loc [ field ] , pReq . vAuthAccount , newLoc ) ; } ; } ; } catch ( err ) { Logger . error ( `procPutUserLocation: exception parsing put from ${ pReq . vAuthAccount . username }: ${ err }` ) ; pReq . vRestResp . respondFailure ( `exception parsing request: ${ err }` ) ; newLoc = undefined ; } ; } ; return newLoc ; } ; export async function buildLocationInfo ( pAcct ) { let ret = { } ; if ( pAcct . locationDomainId ) { const aDomain = await Domains . getDomainWithId ( pAcct . locationDomainId ) ; if ( IsNotNullOrEmpty ( aDomain ) ) { ret = { 'root' : { 'domain' : await buildDomainInfo ( aDomain ) , } , 'path' : pAcct . locationPath , } ; } else { ret = { 'root' : { 'domain' : { 'network_address' : pAcct . locationNetworkAddress , 'network_port' : pAcct . locationNetworkPort } } } ; } ; } ; ret . node_id = pAcct . locationNodeId ; ret . online = Accounts . isOnline ( pAcct ) ; return ret ; } ; export async function buildDomainInfo ( pDomain ) { return { 'id' : pDomain . id , 'domainId' : pDomain . id , 'name' : pDomain . name , 'visibility' : pDomain . visibility ?? Visibility . OPEN , 'capacity' : pDomain . capacity , 'sponsorAccountId' : pDomain . sponsorAccountId , 'label' : pDomain . name , 'network_address' : pDomain . networkAddr , 'network_port' : pDomain . networkPort , 'ice_server_address' : pDomain . iceServerAddr , 'version' : pDomain . version , 'protocol_version' : pDomain . protocol , 'active' : pDomain . active ?? false , 'time_of_last_heartbeat' : pDomain . timeOfLastHeartbeat ?. toISOString ( ) , 'time_of_last_heartbeat_s' : pDomain . timeOfLastHeartbeat ?. getTime ( ) . toString ( ) , 'num_users' : pDomain . numUsers } ; } ; export async function buildDomainInfoV1 ( pDomain ) { return { 'domainId' : pDomain . id , 'id' : pDomain . id , 'name' : pDomain . name , 'visibility' : pDomain . visibility ?? Visibility . OPEN , 'world_name' : pDomain . name , 'label' : pDomain . name , 'public_key' : pDomain . publicKey ? createSimplifiedPublicKey ( pDomain . publicKey ) : undefined , 'owner_places' : await buildPlacesForDomain ( pDomain ) , 'sponsor_account_id' : pDomain . sponsorAccountId , 'ice_server_address' : pDomain . iceServerAddr , 'version' : pDomain . version , 'protocol_version' : pDomain . protocol , 'network_address' : pDomain . networkAddr , 'network_port' : pDomain . networkPort , 'automatic_networking' : pDomain . networkingMode , 'restricted' : pDomain . restricted , 'num_users' : pDomain . numUsers , 'anon_users' : pDomain . anonUsers , 'total_users' : pDomain . numUsers , 'capacity' : pDomain . capacity , 'description' : pDomain . description , 'maturity' : pDomain . maturity ?? Maturity . UNRATED , 'restriction' : pDomain . restriction , 'managers' : pDomain . managers , 'tags' : pDomain . tags , 'meta' : { 'capacity' : pDomain . capacity , 'contact_info' : pDomain . contactInfo , 'description' : pDomain . description , 'images' : pDomain . images , 'managers' : pDomain . managers , 'restriction' : pDomain . restriction , 'tags' : pDomain . tags , 'thumbnail' : pDomain . thumbnail , 'world_name' : pDomain . name } , 'users' : { 'num_anon_users' : pDomain . anonUsers , 'num_users' : pDomain . numUsers , 'user_hostnames' : pDomain . hostnames } , 'time_of_last_heartbeat' : pDomain . timeOfLastHeartbeat ?. toISOString ( ) , 'time_of_last_heartbeat_s' : pDomain . timeOfLastHeartbeat ?. getTime ( ) . toString ( ) , 'last_sender_key' : pDomain . lastSenderKey , 'addr_of_first_contact' : pDomain . iPAddrOfFirstContact , 'when_domain_entry_created' : pDomain . whenCreated ?. toISOString ( ) , 'when_domain_entry_created_s' : pDomain . whenCreated ?. getTime ( ) . toString ( ) } ; } ; export async function buildUserInfo ( pAccount ) { return { 'accountId' : pAccount . id , 'id' : pAccount . id , 'username' : pAccount . username , 'images' : await buildImageInfo ( pAccount ) , 'location' : await buildLocationInfo ( pAccount ) , } ; } ; export async function buildImageInfo ( pAccount ) { const ret = { } ; if ( pAccount . imagesTiny ) ret . tiny = pAccount . imagesTiny ; if ( pAccount . imagesHero ) ret . hero = pAccount . imagesHero ; if ( pAccount . imagesThumbnail ) ret . thumbnail = pAccount . imagesThumbnail ; return ret ; } ; export async function buildAccountInfo ( pReq , pAccount ) { return { 'accountId' : pAccount . id , 'id' : pAccount . id , 'username' : pAccount . username , 'email' : pAccount . email , 'administrator' : Accounts . isAdmin ( pAccount ) , 'enabled' : Accounts . isEnabled ( pAccount ) , 'roles' : pAccount . roles , 'availability' : pAccount . availability , 'public_key' : createSimplifiedPublicKey ( pAccount . sessionPublicKey ) , 'images' : { 'hero' : pAccount . imagesHero , 'tiny' : pAccount . imagesTiny , 'thumbnail' : pAccount . imagesThumbnail } , 'profile_detail' : pAccount . profileDetail , 'location' : await buildLocationInfo ( pAccount ) , 'friends' : pAccount . friends , 'connections' : pAccount . connections , 'when_account_created' : pAccount . whenCreated ?. toISOString ( ) , 'when_account_created_s' : pAccount . whenCreated ?. getTime ( ) . toString ( ) , 'time_of_last_heartbeat' : pAccount . timeOfLastHeartbeat ?. toISOString ( ) , 'time_of_last_heartbeat_s' : pAccount . timeOfLastHeartbeat ?. getTime ( ) . toString ( ) , } ; } ; export async function buildAccountProfile ( pReq , pAccount ) { return { 'accountId' : pAccount . id , 'id' : pAccount . id , 'username' : pAccount . username , 'images' : { 'hero' : pAccount . imagesHero , 'tiny' : pAccount . imagesTiny , 'thumbnail' : pAccount . imagesThumbnail } , 'profile_detail' : pAccount . profileDetail , 'location' : await buildLocationInfo ( pAccount ) , 'when_account_created' : pAccount . whenCreated ?. toISOString ( ) , 'when_account_created_s' : pAccount . whenCreated ?. getTime ( ) . toString ( ) , 'time_of_last_heartbeat' : pAccount . timeOfLastHeartbeat ?. toISOString ( ) , 'time_of_last_heartbeat_s' : pAccount . timeOfLastHeartbeat ?. getTime ( ) . toString ( ) , } ; } ; export async function buildPlaceInfo ( pPlace , pDomain ? ) { const ret = await buildPlaceInfoSmall ( pPlace , pDomain ) ; if ( IsNotNullOrEmpty ( pPlace . domainId ) ) { const aDomain = pDomain ?? await Domains . getDomainWithId ( pPlace . domainId ) ; if ( aDomain ) { ret . domain = await buildDomainInfo ( aDomain ) ; } ; } ; return ret ; } ; export async function buildPlaceInfoSmall ( pPlace , pDomain ? ) { const ret = { 'placeId' : pPlace . id , 'id' : pPlace . id , 'name' : pPlace . name , 'displayName' : pPlace . displayName , 'visibility' : pPlace . visibility ?? Visibility . OPEN , 'address' : await Places . getAddressString ( pPlace ) , 'path' : pPlace . path , 'description' : pPlace . description , 'maturity' : pPlace . maturity ?? Maturity . UNRATED , 'tags' : pPlace . tags , 'managers' : await Places . getManagers ( pPlace ) , 'thumbnail' : pPlace . thumbnail , 'images' : pPlace . images , 'current_attendance' : pPlace . currentAttendance ?? 0 , 'current_images' : pPlace . currentImages , 'current_info' : pPlace . currentInfo , 'current_last_update_time' : pPlace . currentLastUpdateTime ?. toISOString ( ) , 'current_last_update_time_s' : pPlace . currentLastUpdateTime ?. getTime ( ) . toString ( ) , 'last_activity_update' : pPlace . lastActivity ?. toISOString ( ) , 'last_activity_update_s' : pPlace . lastActivity ?. getTime ( ) . toString ( ) } ; return ret ; } ; export async function buildPlacesForDomain ( pDomain ) { const ret = [ ] ; for await ( const aPlace of Places . enumerateAsync ( new GenericFilter ( { 'domainId' : pDomain . id } ) ) ) { ret . push ( await buildPlaceInfoSmall ( aPlace , pDomain ) ) ; } ; return ret ; } ;