src/app/services/licence.service.ts
| providedIn | root |
Properties |
|
Methods |
|
constructor(loggerService: LoggerService, eventService: EventService, sasService: SasService, helperService: HelperService, router: Router)
|
||||||||||||||||||
|
Defined in src/app/services/licence.service.ts:69
|
||||||||||||||||||
|
Parameters :
|
| Public Async activation | ||||||
activation(startupservice: any)
|
||||||
|
Defined in src/app/services/licence.service.ts:87
|
||||||
|
Parameters :
Returns :
any
|
| Private applicationActivation | ||||||||||||||||||||
applicationActivation(licenseData: LicenseKeyData, variables?: Globvar, startup_site_id?: string, skipRouting?: boolean)
|
||||||||||||||||||||
|
Defined in src/app/services/licence.service.ts:210
|
||||||||||||||||||||
|
Checks if:
Parameters :
Returns :
void
|
| Public arrayBufferToBase64 | ||||||
arrayBufferToBase64(arrayBuffer: ArrayBuffer)
|
||||||
|
Defined in src/app/services/licence.service.ts:451
|
||||||
|
Parameters :
Returns :
Promise<string>
|
| Public base64ToArrayBuffer | ||||||
base64ToArrayBuffer(base64: string)
|
||||||
|
Defined in src/app/services/licence.service.ts:445
|
||||||
|
Parameters :
Returns :
Promise<ArrayBuffer>
|
| Private calculateExpiry | ||||||
calculateExpiry(licenseData: LicenseKeyData)
|
||||||
|
Defined in src/app/services/licence.service.ts:517
|
||||||
|
Parameters :
|
| Public checkLineageLimit | ||||||||
checkLineageLimit(checkOnly?: boolean)
|
||||||||
|
Defined in src/app/services/licence.service.ts:415
|
||||||||
|
Checks fo lineage daily renderings limit othervise it will increment number of renderings.
Parameters :
Returns :
boolean
true if limited and false if not limited |
| Public deactivateApp | ||||||
deactivateApp(redirectTo?: string)
|
||||||
|
Defined in src/app/services/licence.service.ts:399
|
||||||
|
Parameters :
Returns :
void
|
| Private decodeLicenceFeatures | ||||||||
decodeLicenceFeatures(licenseData: LicenseKeyData)
|
||||||||
|
Defined in src/app/services/licence.service.ts:276
|
||||||||
|
Decode and set features that are encoded in the key - accepts either an already-issued key's legacy positional string or a newly-issued key's named object, see decodeLicenceFeatures for the format contract.
Parameters :
Returns :
void
|
| Public decryptLicenseKey |
decryptLicenseKey(licenseKey: string, activationKey: string)
|
|
Defined in src/app/services/licence.service.ts:300
|
|
If decryption fails, key will be marked as invalid and app not activated. Public (not just used internally by licensing()) since it's a pure decrypt with no side effects - also used to preview a pasted key's details before it's actually applied.
Returns :
Promise<LicenseKeyData>
|
| Public getHotLicenseKey |
getHotLicenseKey()
|
|
Defined in src/app/services/licence.service.ts:391
|
|
Returns :
any
|
| Public getLicenseKeyData |
getLicenseKeyData()
|
|
Defined in src/app/services/licence.service.ts:395
|
|
Returns :
any
|
| Private handleExpiry | |||||||||||||||
handleExpiry(expiry_date: moment.Moment, variables: Globvar, startup_site_id: string, skipRouting: boolean)
|
|||||||||||||||
|
Defined in src/app/services/licence.service.ts:533
|
|||||||||||||||
|
Parameters :
Returns :
void
|
| Private handleSiteIdMissmatch | |||||||||||||||
handleSiteIdMissmatch(licenseData: LicenseKeyData, variables: Globvar, startup_site_id: string, skipRouting: boolean)
|
|||||||||||||||
|
Defined in src/app/services/licence.service.ts:473
|
|||||||||||||||
|
One of our customers is having multiple site ids in same organization. So we added support for list od site ids to be placed in licence key. But we also want to have dc backwards compatible so we have to check for both properties legacy and new. New key must work with old DC Old key must work with new DC
Parameters :
Returns :
void
|
| Private handleUserRegistration | ||||||||||||
handleUserRegistration(licenseData: LicenseKeyData, variables: Globvar, skipRouting: boolean)
|
||||||||||||
|
Defined in src/app/services/licence.service.ts:570
|
||||||||||||
|
Parameters :
Returns :
void
|
| Private handleUsersAllowed | ||||||
handleUsersAllowed(licenseData: LicenseKeyData)
|
||||||
|
Defined in src/app/services/licence.service.ts:558
|
||||||
|
Parameters :
Returns :
void
|
| Public Async licensing | ||||||||||||
licensing(globvars: Globvar[], startup_site_id: string)
|
||||||||||||
|
Defined in src/app/services/licence.service.ts:112
|
||||||||||||
|
Parsing the licence key, checking if it's valid, expired etc. It also sets the features encoded in the key.
Parameters :
Returns :
unknown
|
| Private setLineageRender |
setLineageRender(timestamp: number, renders: number)
|
|
Defined in src/app/services/licence.service.ts:441
|
|
Returns :
void
|
| Private setSiteId | ||||||
setSiteId(licenseData: LicenseKeyData)
|
||||||
|
Defined in src/app/services/licence.service.ts:457
|
||||||
|
Parameters :
Returns :
void
|
| Public setStartupserviceRules | ||||||||
setStartupserviceRules(startupservice: any)
|
||||||||
|
Defined in src/app/services/licence.service.ts:99
|
||||||||
|
Sets feature restrictions included in startupservice
Parameters :
Returns :
void
|
| Private _licenceState |
Type : LicenceState
|
Default value : freeTierConfig
|
|
Defined in src/app/services/licence.service.ts:35
|
| Public activationKey |
Type : string | undefined
|
|
Defined in src/app/services/licence.service.ts:32
|
| Private allFeaturesOn |
Type : LicenceState
|
Default value : {
viewer_rows_allowed: Infinity,
editor_rows_allowed: Infinity,
stage_rows_allowed: Infinity,
history_rows_allowed: Infinity,
submit_rows_limit: Infinity,
tables_in_library_limit: Infinity,
viewbox_limit: Infinity,
lineage_daily_limit: Infinity,
viewbox: true,
fileUpload: true,
editRecord: true,
addRecord: true
}
|
|
Defined in src/app/services/licence.service.ts:36
|
| Public appLocked |
Type : unknown
|
Default value : new BehaviorSubject<boolean>(false)
|
|
Defined in src/app/services/licence.service.ts:63
|
| Public currentUserCanRegister |
Type : unknown
|
Default value : new BehaviorSubject<boolean>(false)
|
|
Defined in src/app/services/licence.service.ts:62
|
| Private freeTierLicenceData |
Type : LicenseKeyData
|
Default value : {
demo: true,
hot_license_key: DEFAULT_HOT_LICENCE_KEY,
users_allowed: this._licenceState.users_allowed || 1,
valid_until: moment().add(1, 'year').format('YYYY-MM-DD'),
site_id: '',
site_id_multiple: []
}
|
|
Defined in src/app/services/licence.service.ts:51
|
| Public hot_license_key |
Type : unknown
|
Default value : new BehaviorSubject<string | undefined>(undefined)
|
|
Defined in src/app/services/licence.service.ts:67
|
| Public isAppActivated |
Type : unknown
|
Default value : new BehaviorSubject<boolean | null>(null)
|
|
Defined in src/app/services/licence.service.ts:60
|
| Public isAppFreeTier |
Type : unknown
|
Default value : new BehaviorSubject<boolean>(false)
|
|
Defined in src/app/services/licence.service.ts:65
|
| Public isAppOverCapacity |
Type : unknown
|
Default value : new BehaviorSubject<boolean>(false)
|
|
Defined in src/app/services/licence.service.ts:61
|
| Public licenceKey |
Type : string | undefined
|
|
Defined in src/app/services/licence.service.ts:31
|
| Public licenceProblem |
Type : unknown
|
Default value : new BehaviorSubject<string | null>(null)
|
|
Defined in src/app/services/licence.service.ts:66
|
| Public licenceState |
Type : BehaviorSubject<LicenceState>
|
Default value : new BehaviorSubject<LicenceState>(this._licenceState)
|
|
Defined in src/app/services/licence.service.ts:68
|
| Public licenseExpiresInDays |
Type : unknown
|
Default value : new BehaviorSubject<number | null>(null)
|
|
Defined in src/app/services/licence.service.ts:64
|
| Private licenseKeyData |
Type : LicenseKeyData | null
|
Default value : null
|
|
Defined in src/app/services/licence.service.ts:33
|
| Public userCountLimitation |
Type : boolean
|
Default value : false
|
|
Defined in src/app/services/licence.service.ts:29
|
import { Injectable } from '@angular/core'
import { BehaviorSubject } from 'rxjs'
import { LicenseKeyData } from '../models/LicenseKeyData'
import { SasService } from './sas.service'
import moment from 'moment'
import * as base64Converter from 'base64-arraybuffer'
import * as encoding from 'text-encoding'
import { Router } from '@angular/router'
import { Globvar } from '../models/sas/public-startupservice.model'
import { freeTierConfig } from '../free-tier.config'
import { HelperService } from './helper.service'
import { LicenceState } from '../models/LicenceState'
import { decodeLicenceFeatures as decodeFeatures } from './utils/decodeLicenceFeatures'
import { LoggerService } from './logger.service'
import { EventService } from './event.service'
/**
* Handsontable licence key used until a licence is loaded from the backend.
* The decrypted licence carries the customer's own key (`hot_license_key`), so
* this is only the pre-licence / free-tier default - it used to be supplied by
* the `<sasjs>` tag.
*/
export const DEFAULT_HOT_LICENCE_KEY = 'non-commercial-and-evaluation'
@Injectable({
providedIn: 'root'
})
export class LicenceService {
public userCountLimitation: boolean = false //toggler for user count limit registration
public licenceKey: string | undefined
public activationKey: string | undefined
private licenseKeyData: LicenseKeyData | null = null
private _licenceState: LicenceState = freeTierConfig
private allFeaturesOn: LicenceState = {
viewer_rows_allowed: Infinity,
editor_rows_allowed: Infinity,
stage_rows_allowed: Infinity,
history_rows_allowed: Infinity,
submit_rows_limit: Infinity,
tables_in_library_limit: Infinity,
viewbox_limit: Infinity,
lineage_daily_limit: Infinity,
viewbox: true,
fileUpload: true,
editRecord: true,
addRecord: true
}
private freeTierLicenceData: LicenseKeyData = {
demo: true,
hot_license_key: DEFAULT_HOT_LICENCE_KEY,
users_allowed: this._licenceState.users_allowed || 1,
valid_until: moment().add(1, 'year').format('YYYY-MM-DD'),
site_id: '',
site_id_multiple: []
}
public isAppActivated = new BehaviorSubject<boolean | null>(null)
public isAppOverCapacity = new BehaviorSubject<boolean>(false)
public currentUserCanRegister = new BehaviorSubject<boolean>(false)
public appLocked = new BehaviorSubject<boolean>(false)
public licenseExpiresInDays = new BehaviorSubject<number | null>(null)
public isAppFreeTier = new BehaviorSubject<boolean>(false)
public licenceProblem = new BehaviorSubject<string | null>(null) //contains the link for particular licence error if any
public hot_license_key = new BehaviorSubject<string | undefined>(undefined)
public licenceState: BehaviorSubject<LicenceState> =
new BehaviorSubject<LicenceState>(this._licenceState)
constructor(
private loggerService: LoggerService,
private eventService: EventService,
private sasService: SasService,
private helperService: HelperService,
private router: Router
) {
this.sasService.incorrectSiteIdEmitter.subscribe((missmatchId: string) => {
if (this.isAppActivated.value !== null && !this.isAppFreeTier.value) {
const url = `/licensing/key?error=missmatch&missmatchId=${missmatchId}&force=true`
this.licenceProblem.next(url)
this.deactivateApp(url)
}
})
}
public async activation(startupservice: any) {
this.freeTierLicenceData.hot_license_key = DEFAULT_HOT_LICENCE_KEY
await this.setStartupserviceRules(startupservice)
await this.licensing(startupservice.globvars, startupservice.SYSSITE)
}
/**
* Sets feature restrictions included in startupservice
* @param startupservice SAS service response
*/
public setStartupserviceRules(startupservice: any) {
// Whether or not to disable EDIT RECORD modal
this._licenceState.editRecord = !(
startupservice.globvars[0].DC_RESTRICT_EDITRECORD === 'YES'
)
}
/**
* Parsing the licence key, checking if it's valid, expired etc.
* It also sets the features encoded in the key.
* @param globvars from response, includes licence key, is user registered and user registered count
* @param startup_site_id system site id
*/
public async licensing(globvars: Globvar[], startup_site_id: string) {
if (!globvars || !globvars[0]) {
const err = 'Error getting "Globvars" from startupservice response.'
console.error(err)
this.isAppActivated.next(false)
this.router.navigateByUrl(
`/licensing/key?error=invalid&details=${btoa(err)}`
)
return
}
let variables = globvars[0]
// Trim whitespace — the SAS makedata service initialises licence keys
// as a single space, which is truthy in JS but not a valid key.
if (variables.LICENCE_KEY)
variables.LICENCE_KEY = variables.LICENCE_KEY.trim()
if (variables.ACTIVATION_KEY)
variables.ACTIVATION_KEY = variables.ACTIVATION_KEY.trim()
if (
variables.LICENCE_KEY === undefined ||
variables.ACTIVATION_KEY === undefined ||
variables.REGISTERCOUNT === null ||
variables.REGISTERCOUNT === undefined ||
variables.ISREGISTERED === null ||
variables.ISREGISTERED === undefined
) {
console.error('Some of globvars are not present')
this.isAppActivated.next(false)
this.eventService.showInfoModal(
'Error',
'Some of the globvars are not present in the startupservice',
'public/startupservice'
)
// this.router.navigateByUrl('/licensing/key?error=missing')
return
}
if (!variables.LICENCE_KEY || !variables.ACTIVATION_KEY) {
//fall back to free tier if key not present
// setTimeout(() => {
return await this.applicationActivation(
this.freeTierLicenceData,
variables,
startup_site_id
)
// })
// return
}
this.licenceKey = variables.LICENCE_KEY
this.activationKey = variables.ACTIVATION_KEY
await this.decryptLicenseKey(
variables.LICENCE_KEY,
variables.ACTIVATION_KEY
).then(
async (decryptedLicenseData: LicenseKeyData) => {
await this.applicationActivation(
decryptedLicenseData,
variables,
startup_site_id
)
},
async (err: any) => {
const errString = `Error decrypting license key. ${err}`
console.error(errString)
// this.isAppActivated.next(false)
const url = `/licensing/key?error=invalid&details=${btoa(
errString
)}&force=true`
this.licenceProblem.next(url)
setTimeout(() => {
this.applicationActivation(
this.freeTierLicenceData,
variables,
startup_site_id,
true
)
this.router.navigateByUrl(url)
})
}
)
}
/**
* Checks if:
* - site id match
* - key is/isn't expired
* - user can be registered (user limit)
* @param licenseData
* @param variables from SAS response
* @param startup_site_id of current sas environment
*/
private applicationActivation(
licenseData: LicenseKeyData,
variables?: Globvar,
startup_site_id?: string,
skipRouting?: boolean
) {
if (!skipRouting) skipRouting = false
this.setSiteId(licenseData)
if (!licenseData.demo && variables && startup_site_id) {
this.handleSiteIdMissmatch(
licenseData,
variables,
startup_site_id,
skipRouting
)
}
let hotLicenceKey =
licenseData.hot_license_key !== undefined
? licenseData.hot_license_key
: this.hot_license_key.value
if (!hotLicenceKey) hotLicenceKey = DEFAULT_HOT_LICENCE_KEY
this.hot_license_key.next(hotLicenceKey)
if (this.userCountLimitation) {
this.handleUsersAllowed(licenseData)
}
this.licenseKeyData = this.helperService.deepClone(licenseData)
;(window as any).appinfo() //Show the table of appinfo in the console
const { expiry_date, daysToExpiry } = this.calculateExpiry(licenseData)
;(window as any).licenseExpiresIn = daysToExpiry
this.licenseExpiresInDays.next(daysToExpiry)
if (daysToExpiry <= 0) {
console.error('License key has expired')
if (variables && startup_site_id) {
this.handleExpiry(expiry_date, variables, startup_site_id, skipRouting)
}
return
}
this.isAppFreeTier.next(!!licenseData.demo)
if (variables) {
this.handleUserRegistration(licenseData, variables, skipRouting)
}
this.decodeLicenceFeatures(licenseData)
this.licenceState.next(this._licenceState) //set the global licence state
}
/**
* Decode and set features that are encoded in the key - accepts either
* an already-issued key's legacy positional string or a newly-issued
* key's named object, see decodeLicenceFeatures for the format contract.
* @param licenseData from the licence key
*/
private decodeLicenceFeatures(licenseData: LicenseKeyData) {
if (!licenseData.features) {
if (licenseData.demo) {
return
} else {
this._licenceState = this.allFeaturesOn
return
}
}
this._licenceState = {
...this._licenceState,
...decodeFeatures(licenseData.features)
}
this.loggerService.log('Licence state:', this._licenceState)
}
/**
* If decryption fails, key will be marked as invalid and app not activated.
* Public (not just used internally by licensing()) since it's a pure
* decrypt with no side effects - also used to preview a pasted key's
* details before it's actually applied.
*/
public decryptLicenseKey(
licenseKey: string,
activationKey: string
): Promise<LicenseKeyData> {
return new Promise<LicenseKeyData>(async (resolve, reject) => {
if (!(window.crypto && window.crypto.subtle)) {
try {
let licenseKeyDecoded = atob(licenseKey.split('').reverse().join(''))
resolve(JSON.parse(licenseKeyDecoded))
} catch (ex) {
reject('Error parsing http license key data. ' + ex)
}
}
let licenseKeyBytes = await this.base64ToArrayBuffer(licenseKey).catch(
(err: any) => {
reject(err)
}
)
let activationKeyBytes: ArrayBuffer
const activationKeyBytesTemp = await this.base64ToArrayBuffer(
activationKey
).catch((err: any) => {
reject(err)
})
if (!activationKeyBytesTemp) {
reject('Missing activation key')
return
}
activationKeyBytes = activationKeyBytesTemp
let decryptionKey
try {
decryptionKey = await window.crypto.subtle.importKey(
'pkcs8',
activationKeyBytes,
{
name: 'RSA-OAEP',
hash: 'SHA-256'
},
true,
['decrypt']
)
} catch (ex) {
reject('Unable to import decryption key: ' + ex)
}
if (!decryptionKey) {
reject('Unable to import decryption key')
return
}
if (!licenseKeyBytes) {
reject('License key bytes missing')
} else {
try {
window.crypto.subtle
.decrypt(
{
name: 'RSA-OAEP',
hash: { name: 'SHA-256' }
} as any,
decryptionKey,
licenseKeyBytes
)
.then(
(value: any) => {
let keyDataString = new encoding.TextDecoder().decode(value)
try {
resolve(JSON.parse(keyDataString))
} catch (ex) {
reject('Error parsing license key data. ' + ex)
}
},
(err: any) => {
reject(err)
}
)
} catch (ex) {
reject(ex)
}
}
})
}
public getHotLicenseKey() {
return this.hot_license_key.value
}
public getLicenseKeyData() {
return this.licenseKeyData
}
public deactivateApp(redirectTo?: string) {
// this.isAppActivated.next(false)
this._licenceState = freeTierConfig
this.applicationActivation(this.freeTierLicenceData)
if (redirectTo) this.router.navigateByUrl(redirectTo)
}
/**
* Checks fo lineage daily renderings limit
*
* @param checkOnly if true it will only check if limit reached
* othervise it will increment number of renderings.
* @returns true if limited and false if not limited
*/
public checkLineageLimit(checkOnly?: boolean): boolean {
if (this.licenceState.value.lineage_daily_limit === Infinity) return false
const renders = localStorage.getItem('lineage_renders')
const todayTimestamp = moment().valueOf()
if (!renders) {
if (!checkOnly) this.setLineageRender(todayTimestamp, 1)
return false
}
const timestamp = parseInt(renders.split(',')[0])
const noOfRenders = parseInt(renders.split(',')[1])
if (moment(timestamp).isSame(moment(), 'day')) {
if (noOfRenders >= this.licenceState.value.lineage_daily_limit)
return true
if (!checkOnly) this.setLineageRender(todayTimestamp, noOfRenders + 1)
return false
}
if (!checkOnly) this.setLineageRender(todayTimestamp, 1)
return false
}
private setLineageRender(timestamp: number, renders: number) {
localStorage.setItem('lineage_renders', `${timestamp},${renders}`)
}
public base64ToArrayBuffer(base64: string): Promise<ArrayBuffer> {
return new Promise(async (resolve, reject) => {
resolve(base64Converter.decode(base64))
})
}
public arrayBufferToBase64(arrayBuffer: ArrayBuffer): Promise<string> {
return new Promise((resolve, reject) => {
resolve(base64Converter.encode(arrayBuffer))
})
}
private setSiteId(licenseData: LicenseKeyData) {
if (licenseData.site_id_multiple) {
this.sasService.setLicenseSiteId(licenseData.site_id_multiple)
} else if (licenseData.site_id) {
this.sasService.setLicenseSiteId(licenseData.site_id)
}
}
/**
* One of our customers is having multiple site ids in same organization.
* So we added support for list od site ids to be placed in licence key.
* But we also want to have dc backwards compatible so we have to check
* for both properties legacy and new.
* New key must work with old DC
* Old key must work with new DC
*/
private handleSiteIdMissmatch(
licenseData: LicenseKeyData,
variables: Globvar,
startup_site_id: string,
skipRouting: boolean
) {
let noLegacySiteId: boolean = false
let noMultipleSiteId: boolean = false
if (!licenseData.site_id || licenseData.site_id !== startup_site_id) {
noLegacySiteId = true
}
if (
!licenseData.site_id_multiple ||
!licenseData.site_id_multiple.includes(startup_site_id)
) {
noMultipleSiteId = true
}
if (noLegacySiteId && noMultipleSiteId) {
console.error('The key provided is for different organization.')
// this.isAppActivated.next(false)
setTimeout(() => {
const url = '/licensing/key?error=missmatch&force=true'
this.licenceProblem.next(url)
this._licenceState = freeTierConfig
this.applicationActivation(
this.freeTierLicenceData,
variables,
startup_site_id,
true
)
if (!skipRouting) this.router.navigateByUrl(url)
})
return
}
}
private calculateExpiry(licenseData: LicenseKeyData): {
expiry_date: moment.Moment
daysToExpiry: number
} {
let expiry_date = moment(licenseData.valid_until, 'YYYY-MM-DD').startOf(
'day'
)
let current_date = moment().startOf('day')
let daysToExpiry = expiry_date.diff(current_date, 'days')
return {
expiry_date,
daysToExpiry
}
}
private handleExpiry(
expiry_date: moment.Moment,
variables: Globvar,
startup_site_id: string,
skipRouting: boolean
) {
setTimeout(() => {
const url = `/licensing/key?force=true&error=expired&details=${btoa(
'Expiry date: ' + expiry_date.format('DD/MM/YYYY')
)}`
this.licenceProblem.next(url)
// Instead of blocking the app we revert to free tier version of the app
this.applicationActivation(
this.freeTierLicenceData,
variables,
startup_site_id,
true
)
if (!skipRouting) {
this.router.navigateByUrl(url)
}
})
}
private handleUsersAllowed(licenseData: LicenseKeyData) {
if (licenseData.demo) {
if (this._licenceState.users_allowed !== undefined)
licenseData.users_allowed =
licenseData.users_allowed > 0
? licenseData.users_allowed
: this._licenceState.users_allowed
}
this._licenceState.users_allowed = licenseData.users_allowed
}
private handleUserRegistration(
licenseData: LicenseKeyData,
variables: Globvar,
skipRouting: boolean
) {
if (this.userCountLimitation) {
//if limit disabled we don't track the count
if (variables.REGISTERCOUNT > licenseData.users_allowed) {
//App is over capacity of users
console.warn('App has more users registered then licensed.')
this.isAppOverCapacity.next(true)
} else if (variables.REGISTERCOUNT === licenseData.users_allowed) {
//App reached capacity of users
console.warn('App has hit limit of users registered.')
}
}
if (variables.ISREGISTERED === 1) {
this.isAppActivated.next(true)
return
} else {
// if limit is disabled we always go into register directly
if (
variables.REGISTERCOUNT < licenseData.users_allowed ||
!this.userCountLimitation
) {
console.log('User can register')
this.currentUserCanRegister.next(true)
// this.appLocked.next(true)
this.isAppActivated.next(false)
if (!skipRouting) this.router.navigateByUrl('/licensing/register')
//After register, activate app
return
} else {
this.currentUserCanRegister.next(false)
this.isAppActivated.next(false)
// this.appLocked.next(true)
if (!skipRouting) this.router.navigateByUrl('/licensing/limit')
}
}
}
}