feat: lots more improvements
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
@@ -10,18 +10,55 @@ import type {
|
||||
ServiceIdentityOAuth,
|
||||
ServiceIdentityCertificate
|
||||
} from '@/types/service';
|
||||
import { MutationProxy } from './mutation-proxy';
|
||||
import { clonePlain } from './clone-plain';
|
||||
|
||||
/**
|
||||
* Base Identity class
|
||||
*/
|
||||
export abstract class Identity {
|
||||
abstract toJson(): ServiceIdentity;
|
||||
abstract clone(): Identity;
|
||||
export abstract class Identity<T extends ServiceIdentity = ServiceIdentity> {
|
||||
protected _original: T;
|
||||
protected _mutated: Partial<T>;
|
||||
protected _mutationProxy: MutationProxy<T>;
|
||||
protected _data: T;
|
||||
|
||||
protected constructor(initial: T) {
|
||||
this._original = clonePlain(initial);
|
||||
this._mutated = {};
|
||||
this._mutationProxy = new MutationProxy<T>(() => this._original, () => this._mutated);
|
||||
this._data = this._mutationProxy.create();
|
||||
}
|
||||
|
||||
protected load(data: T): this {
|
||||
this._original = clonePlain(data);
|
||||
this._mutated = {};
|
||||
this._data = this._mutationProxy.create();
|
||||
return this;
|
||||
}
|
||||
|
||||
toJSON(): ServiceIdentity {
|
||||
return this.toJson();
|
||||
}
|
||||
|
||||
toJson(): T;
|
||||
toJson(delta: true): Partial<T>;
|
||||
toJson(delta?: boolean): T | Partial<T> {
|
||||
if (delta) {
|
||||
return clonePlain(this._mutated);
|
||||
}
|
||||
|
||||
return {
|
||||
...clonePlain(this._original),
|
||||
...clonePlain(this._mutated),
|
||||
};
|
||||
}
|
||||
|
||||
abstract clone(): Identity;
|
||||
|
||||
mutated(): boolean {
|
||||
return Reflect.ownKeys(this._mutated).length > 0;
|
||||
}
|
||||
|
||||
static fromJson(data: ServiceIdentity): Identity {
|
||||
switch (data.type) {
|
||||
case 'NA':
|
||||
@@ -43,48 +80,47 @@ export abstract class Identity {
|
||||
/**
|
||||
* No authentication
|
||||
*/
|
||||
export class IdentityNone extends Identity {
|
||||
|
||||
private _data: ServiceIdentityNone;
|
||||
export class IdentityNone extends Identity<ServiceIdentityNone> {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._data = {
|
||||
super({
|
||||
type: 'NA'
|
||||
};
|
||||
}
|
||||
|
||||
get type(): 'NA' {
|
||||
return this._data.type;
|
||||
});
|
||||
}
|
||||
|
||||
static fromJson(_data: ServiceIdentityNone): IdentityNone {
|
||||
return new IdentityNone();
|
||||
}
|
||||
|
||||
toJson(): ServiceIdentityNone {
|
||||
return { ...this._data };
|
||||
}
|
||||
|
||||
clone(): IdentityNone {
|
||||
return IdentityNone.fromJson(this.toJson());
|
||||
}
|
||||
|
||||
get type(): 'NA' {
|
||||
return this._data.type;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic authentication (username/password)
|
||||
*/
|
||||
export class IdentityBasic extends Identity {
|
||||
|
||||
private _data: ServiceIdentityBasic;
|
||||
export class IdentityBasic extends Identity<ServiceIdentityBasic> {
|
||||
|
||||
constructor(identity: string = '', secret: string = '') {
|
||||
super();
|
||||
this._data = {
|
||||
super({
|
||||
type: 'BA',
|
||||
identity,
|
||||
secret
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
static fromJson(data: ServiceIdentityBasic): IdentityBasic {
|
||||
return new IdentityBasic().load(data);
|
||||
}
|
||||
|
||||
clone(): IdentityBasic {
|
||||
return IdentityBasic.fromJson(this.toJson());
|
||||
}
|
||||
|
||||
get type(): 'BA' {
|
||||
@@ -107,32 +143,26 @@ export class IdentityBasic extends Identity {
|
||||
this._data.secret = value;
|
||||
}
|
||||
|
||||
static fromJson(data: ServiceIdentityBasic): IdentityBasic {
|
||||
return new IdentityBasic(data.identity, data.secret);
|
||||
}
|
||||
|
||||
toJson(): ServiceIdentityBasic {
|
||||
return { ...this._data };
|
||||
}
|
||||
|
||||
clone(): IdentityBasic {
|
||||
return IdentityBasic.fromJson(this.toJson());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Token authentication (API key, static token)
|
||||
*/
|
||||
export class IdentityToken extends Identity {
|
||||
|
||||
private _data: ServiceIdentityToken;
|
||||
export class IdentityToken extends Identity<ServiceIdentityToken> {
|
||||
|
||||
constructor(token: string = '') {
|
||||
super();
|
||||
this._data = {
|
||||
super({
|
||||
type: 'TA',
|
||||
token
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
static fromJson(data: ServiceIdentityToken): IdentityToken {
|
||||
return new IdentityToken().load(data);
|
||||
}
|
||||
|
||||
clone(): IdentityToken {
|
||||
return IdentityToken.fromJson(this.toJson());
|
||||
}
|
||||
|
||||
get type(): 'TA' {
|
||||
@@ -147,25 +177,12 @@ export class IdentityToken extends Identity {
|
||||
this._data.token = value;
|
||||
}
|
||||
|
||||
static fromJson(data: ServiceIdentityToken): IdentityToken {
|
||||
return new IdentityToken(data.token);
|
||||
}
|
||||
|
||||
toJson(): ServiceIdentityToken {
|
||||
return { ...this._data };
|
||||
}
|
||||
|
||||
clone(): IdentityToken {
|
||||
return IdentityToken.fromJson(this.toJson());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* OAuth authentication
|
||||
*/
|
||||
export class IdentityOAuth extends Identity {
|
||||
|
||||
private _data: ServiceIdentityOAuth;
|
||||
export class IdentityOAuth extends Identity<ServiceIdentityOAuth> {
|
||||
|
||||
constructor(
|
||||
accessToken: string = '',
|
||||
@@ -174,15 +191,32 @@ export class IdentityOAuth extends Identity {
|
||||
refreshToken?: string,
|
||||
refreshLocation?: string
|
||||
) {
|
||||
super();
|
||||
this._data = {
|
||||
super({
|
||||
type: 'OA',
|
||||
accessToken,
|
||||
accessScope,
|
||||
accessExpiry,
|
||||
refreshToken,
|
||||
refreshLocation
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
static fromJson(data: ServiceIdentityOAuth): IdentityOAuth {
|
||||
return new IdentityOAuth().load(data);
|
||||
}
|
||||
|
||||
clone(): IdentityOAuth {
|
||||
return IdentityOAuth.fromJson(this.toJson());
|
||||
}
|
||||
|
||||
isExpired(): boolean {
|
||||
if (!this.accessExpiry) return false;
|
||||
return Date.now() / 1000 >= this.accessExpiry;
|
||||
}
|
||||
|
||||
expiresIn(): number {
|
||||
if (!this.accessExpiry) return Infinity;
|
||||
return Math.max(0, this.accessExpiry - Date.now() / 1000);
|
||||
}
|
||||
|
||||
get type(): 'OA' {
|
||||
@@ -198,11 +232,11 @@ export class IdentityOAuth extends Identity {
|
||||
}
|
||||
|
||||
get accessScope(): string[] | undefined {
|
||||
return this._data.accessScope;
|
||||
return this._data.accessScope ? [...this._data.accessScope] : undefined;
|
||||
}
|
||||
|
||||
set accessScope(value: string[] | undefined) {
|
||||
this._data.accessScope = value;
|
||||
this._data.accessScope = value ? [...value] : undefined;
|
||||
}
|
||||
|
||||
get accessExpiry(): number | undefined {
|
||||
@@ -229,56 +263,28 @@ export class IdentityOAuth extends Identity {
|
||||
this._data.refreshLocation = value;
|
||||
}
|
||||
|
||||
static fromJson(data: ServiceIdentityOAuth): IdentityOAuth {
|
||||
return new IdentityOAuth(
|
||||
data.accessToken,
|
||||
data.accessScope,
|
||||
data.accessExpiry,
|
||||
data.refreshToken,
|
||||
data.refreshLocation
|
||||
);
|
||||
}
|
||||
|
||||
toJson(): ServiceIdentityOAuth {
|
||||
return {
|
||||
type: this.type,
|
||||
accessToken: this.accessToken,
|
||||
...(this.accessScope !== undefined && { accessScope: [...this.accessScope] }),
|
||||
...(this.accessExpiry !== undefined && { accessExpiry: this.accessExpiry }),
|
||||
...(this.refreshToken !== undefined && { refreshToken: this.refreshToken }),
|
||||
...(this.refreshLocation !== undefined && { refreshLocation: this.refreshLocation })
|
||||
};
|
||||
}
|
||||
|
||||
clone(): IdentityOAuth {
|
||||
return IdentityOAuth.fromJson(this.toJson());
|
||||
}
|
||||
|
||||
isExpired(): boolean {
|
||||
if (!this.accessExpiry) return false;
|
||||
return Date.now() / 1000 >= this.accessExpiry;
|
||||
}
|
||||
|
||||
expiresIn(): number {
|
||||
if (!this.accessExpiry) return Infinity;
|
||||
return Math.max(0, this.accessExpiry - Date.now() / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Client certificate authentication (mTLS)
|
||||
*/
|
||||
export class IdentityCertificate extends Identity {
|
||||
private _data: ServiceIdentityCertificate;
|
||||
export class IdentityCertificate extends Identity<ServiceIdentityCertificate> {
|
||||
|
||||
constructor(certificate: string = '', privateKey: string = '', passphrase?: string) {
|
||||
super();
|
||||
this._data = {
|
||||
super({
|
||||
type: 'CC',
|
||||
certificate,
|
||||
privateKey,
|
||||
passphrase
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
static fromJson(data: ServiceIdentityCertificate): IdentityCertificate {
|
||||
return new IdentityCertificate().load(data);
|
||||
}
|
||||
|
||||
clone(): IdentityCertificate {
|
||||
return IdentityCertificate.fromJson(this.toJson());
|
||||
}
|
||||
|
||||
get type(): 'CC' {
|
||||
@@ -309,24 +315,4 @@ export class IdentityCertificate extends Identity {
|
||||
this._data.passphrase = value;
|
||||
}
|
||||
|
||||
static fromJson(data: ServiceIdentityCertificate): IdentityCertificate {
|
||||
return new IdentityCertificate(
|
||||
data.certificate,
|
||||
data.privateKey,
|
||||
data.passphrase
|
||||
);
|
||||
}
|
||||
|
||||
toJson(): ServiceIdentityCertificate {
|
||||
return {
|
||||
type: this.type,
|
||||
certificate: this.certificate,
|
||||
privateKey: this.privateKey,
|
||||
...(this.passphrase !== undefined && { passphrase: this.passphrase })
|
||||
};
|
||||
}
|
||||
|
||||
clone(): IdentityCertificate {
|
||||
return IdentityCertificate.fromJson(this.toJson());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user