2023-05-30 12:27:04 +03:00

253 lines
8.5 KiB
TypeScript

import { Injectable } from '@angular/core';
import { FuseMockApiService } from '@fuse/lib/mock-api';
import { user as userData } from 'app/mock-api/common/user/data';
import Base64 from 'crypto-js/enc-base64';
import Utf8 from 'crypto-js/enc-utf8';
import HmacSHA256 from 'crypto-js/hmac-sha256';
import { cloneDeep } from 'lodash-es';
@Injectable({providedIn: 'root'})
export class AuthMockApi
{
private readonly _secret: any;
private _user: any = userData;
/**
* Constructor
*/
constructor(private _fuseMockApiService: FuseMockApiService)
{
// Set the mock-api
this._secret = 'YOUR_VERY_CONFIDENTIAL_SECRET_FOR_SIGNING_JWT_TOKENS!!!';
// Register Mock API handlers
this.registerHandlers();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Register Mock API handlers
*/
registerHandlers(): void
{
// -----------------------------------------------------------------------------------------------------
// @ Forgot password - POST
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPost('api/auth/forgot-password', 1000)
.reply(() =>
[
200,
true,
],
);
// -----------------------------------------------------------------------------------------------------
// @ Reset password - POST
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPost('api/auth/reset-password', 1000)
.reply(() =>
[
200,
true,
],
);
// -----------------------------------------------------------------------------------------------------
// @ Sign in - POST
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPost('api/auth/sign-in', 1500)
.reply(({request}) =>
{
// Sign in successful
if ( request.body.email === 'hughes.brian@company.com' && request.body.password === 'admin' )
{
return [
200,
{
user : cloneDeep(this._user),
accessToken: this._generateJWTToken(),
tokenType : 'bearer',
},
];
}
// Invalid credentials
return [
404,
false,
];
});
// -----------------------------------------------------------------------------------------------------
// @ Sign in using the access token - POST
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPost('api/auth/sign-in-with-token')
.reply(({request}) =>
{
// Get the access token
const accessToken = request.body.accessToken;
// Verify the token
if ( this._verifyJWTToken(accessToken) )
{
return [
200,
{
user : cloneDeep(this._user),
accessToken: this._generateJWTToken(),
tokenType : 'bearer',
},
];
}
// Invalid token
return [
401,
{
error: 'Invalid token',
},
];
});
// -----------------------------------------------------------------------------------------------------
// @ Sign up - POST
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPost('api/auth/sign-up', 1500)
.reply(() =>
// Simply return true
[
200,
true,
],
);
// -----------------------------------------------------------------------------------------------------
// @ Unlock session - POST
// -----------------------------------------------------------------------------------------------------
this._fuseMockApiService
.onPost('api/auth/unlock-session', 1500)
.reply(({request}) =>
{
// Sign in successful
if ( request.body.email === 'hughes.brian@company.com' && request.body.password === 'admin' )
{
return [
200,
{
user : cloneDeep(this._user),
accessToken: this._generateJWTToken(),
tokenType : 'bearer',
},
];
}
// Invalid credentials
return [
404,
false,
];
});
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Return base64 encoded version of the given string
*
* @param source
* @private
*/
private _base64url(source: any): string
{
// Encode in classical base64
let encodedSource = Base64.stringify(source);
// Remove padding equal characters
encodedSource = encodedSource.replace(/=+$/, '');
// Replace characters according to base64url specifications
encodedSource = encodedSource.replace(/\+/g, '-');
encodedSource = encodedSource.replace(/\//g, '_');
// Return the base64 encoded string
return encodedSource;
}
/**
* Generates a JWT token using CryptoJS library.
*
* This generator is for mocking purposes only and it is NOT
* safe to use it in production frontend applications!
*
* @private
*/
private _generateJWTToken(): string
{
// Define token header
const header = {
alg: 'HS256',
typ: 'JWT',
};
// Calculate the issued at and expiration dates
const date = new Date();
const iat = Math.floor(date.getTime() / 1000);
const exp = Math.floor((date.setDate(date.getDate() + 7)) / 1000);
// Define token payload
const payload = {
iat: iat,
iss: 'Fuse',
exp: exp,
};
// Stringify and encode the header
const stringifiedHeader = Utf8.parse(JSON.stringify(header));
const encodedHeader = this._base64url(stringifiedHeader);
// Stringify and encode the payload
const stringifiedPayload = Utf8.parse(JSON.stringify(payload));
const encodedPayload = this._base64url(stringifiedPayload);
// Sign the encoded header and mock-api
let signature: any = encodedHeader + '.' + encodedPayload;
signature = HmacSHA256(signature, this._secret);
signature = this._base64url(signature);
// Build and return the token
return encodedHeader + '.' + encodedPayload + '.' + signature;
}
/**
* Verify the given token
*
* @param token
* @private
*/
private _verifyJWTToken(token: string): boolean
{
// Split the token into parts
const parts = token.split('.');
const header = parts[0];
const payload = parts[1];
const signature = parts[2];
// Re-sign and encode the header and payload using the secret
const signatureCheck = this._base64url(HmacSHA256(header + '.' + payload, this._secret));
// Verify that the resulting signature is valid
return (signature === signatureCheck);
}
}