diff --git a/.gitignore b/.gitignore index 2c2d695..5970bfb 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,9 @@ node_modules # ignore coverage folder coverage .nyc_output + +# makes bun optional +bun.lockb + +# ignore final build files +lib \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit index f7042b9..1bda9c1 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,4 @@ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" -npm run build && npm run format +npm run format diff --git a/lib/auth-action.d.ts b/lib/auth-action.d.ts deleted file mode 100644 index 7c7440a..0000000 --- a/lib/auth-action.d.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { TokenResponse } from '@openid/appauth'; -export declare enum AuthActions { - Init = 'Init', - SignInSuccess = 'Sign In Success', - SignInFailed = 'Sign In Failed', - SignOutSuccess = 'Sign Out Success', - SignOutFailed = 'Sign Out Failed', - RefreshSuccess = 'Refresh Success', - RefreshFailed = 'Refesh Failed', - LoadTokenFromStorageSuccess = 'Get Token From Storage Success', - LoadTokenFromStorageFailed = 'Get Token From Storage Failed', - LoadUserInfoSuccess = 'Load User Info Success', - LoadUserInfoFailed = 'Load User Info Failed', - RevokeTokensSuccess = 'Revoke Tokens Success', - RevokeTokensFailed = 'Revoke Tokens Failed', -} -export interface IAuthAction { - action: string; - tokenResponse?: TokenResponse; - error?: string; - user?: any; -} -export declare class AuthActionBuilder { - static Init(): IAuthAction; - static SignOutSuccess(): IAuthAction; - static SignOutFailed(error: any): IAuthAction; - static RefreshSuccess(tokenResponse: TokenResponse): IAuthAction; - static RefreshFailed(error: any): IAuthAction; - static SignInSuccess(tokenResponse: TokenResponse): IAuthAction; - static SignInFailed(error: any): IAuthAction; - static LoadTokenFromStorageSuccess(tokenResponse: TokenResponse): IAuthAction; - static LoadTokenFromStorageFailed(error: any): IAuthAction; - static RevokeTokensSuccess(): IAuthAction; - static RevokeTokensFailed(error: any): IAuthAction; - static LoadUserInfoSuccess(user: any): IAuthAction; - static LoadUserInfoFailed(error: any): IAuthAction; -} diff --git a/lib/auth-action.js b/lib/auth-action.js deleted file mode 100644 index c4dc427..0000000 --- a/lib/auth-action.js +++ /dev/null @@ -1,94 +0,0 @@ -export var AuthActions; -(function (AuthActions) { - AuthActions['Init'] = 'Init'; - AuthActions['SignInSuccess'] = 'Sign In Success'; - AuthActions['SignInFailed'] = 'Sign In Failed'; - AuthActions['SignOutSuccess'] = 'Sign Out Success'; - AuthActions['SignOutFailed'] = 'Sign Out Failed'; - AuthActions['RefreshSuccess'] = 'Refresh Success'; - AuthActions['RefreshFailed'] = 'Refesh Failed'; - AuthActions['LoadTokenFromStorageSuccess'] = 'Get Token From Storage Success'; - AuthActions['LoadTokenFromStorageFailed'] = 'Get Token From Storage Failed'; - AuthActions['LoadUserInfoSuccess'] = 'Load User Info Success'; - AuthActions['LoadUserInfoFailed'] = 'Load User Info Failed'; - AuthActions['RevokeTokensSuccess'] = 'Revoke Tokens Success'; - AuthActions['RevokeTokensFailed'] = 'Revoke Tokens Failed'; -})(AuthActions || (AuthActions = {})); -export class AuthActionBuilder { - static Init() { - return { - action: AuthActions.Init, - }; - } - static SignOutSuccess() { - return { - action: AuthActions.SignOutSuccess, - }; - } - static SignOutFailed(error) { - return { - action: AuthActions.SignOutFailed, - error: error.message, - }; - } - static RefreshSuccess(tokenResponse) { - return { - action: AuthActions.RefreshSuccess, - tokenResponse, - }; - } - static RefreshFailed(error) { - return { - action: AuthActions.RefreshFailed, - error: error.message, - }; - } - static SignInSuccess(tokenResponse) { - return { - action: AuthActions.SignInSuccess, - tokenResponse, - }; - } - static SignInFailed(error) { - return { - action: AuthActions.SignInFailed, - error: error.message, - }; - } - static LoadTokenFromStorageSuccess(tokenResponse) { - return { - action: AuthActions.LoadTokenFromStorageSuccess, - tokenResponse, - }; - } - static LoadTokenFromStorageFailed(error) { - return { - action: AuthActions.LoadTokenFromStorageFailed, - error: error.message, - }; - } - static RevokeTokensSuccess() { - return { - action: AuthActions.RevokeTokensSuccess, - tokenResponse: undefined, - }; - } - static RevokeTokensFailed(error) { - return { - action: AuthActions.RevokeTokensFailed, - error: error.message, - }; - } - static LoadUserInfoSuccess(user) { - return { - action: AuthActions.LoadUserInfoSuccess, - user, - }; - } - static LoadUserInfoFailed(error) { - return { - action: AuthActions.LoadUserInfoFailed, - error: error.message, - }; - } -} diff --git a/lib/auth-browser.d.ts b/lib/auth-browser.d.ts deleted file mode 100644 index db35f8d..0000000 --- a/lib/auth-browser.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -export declare abstract class Browser { - protected onCloseFunction: Function; - abstract showWindow(url: string, callbackUrl?: string): string | undefined | Promise; - abstract closeWindow(): void | Promise; - browserCloseListener(closeBrowserEvent: Function): void; -} -export declare class DefaultBrowser extends Browser { - showWindow(url: string): string | undefined; - closeWindow(): void; -} diff --git a/lib/auth-browser.js b/lib/auth-browser.js deleted file mode 100644 index efcc593..0000000 --- a/lib/auth-browser.js +++ /dev/null @@ -1,21 +0,0 @@ -export class Browser { - constructor() { - this.onCloseFunction = () => {}; - } - browserCloseListener(closeBrowserEvent) { - this.onCloseFunction = closeBrowserEvent; - } -} -export class DefaultBrowser extends Browser { - showWindow(url) { - const openWindow = window.open(url, '_self'); - if (openWindow) { - openWindow.addEventListener('beforeupload', () => this.onCloseFunction()); - } - return; - } - closeWindow() { - // Invoking window.close() is not desired. It will either be ignored (most of the time), - // or it will close the current browser tab if this site was opened via a "_blank" target. - } -} diff --git a/lib/auth-configuration.d.ts b/lib/auth-configuration.d.ts deleted file mode 100644 index 5aae9d9..0000000 --- a/lib/auth-configuration.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -export declare enum AuthenticationType { - Token = 'token', - AuthorizationCode = 'code', - IdToken = 'id_token', -} -export interface IAuthConfig { - client_id: string; - client_secret?: string; - server_host: string; - redirect_url: string; - end_session_redirect_url: string; - scopes: string; - pkce: boolean; -} diff --git a/lib/auth-configuration.js b/lib/auth-configuration.js deleted file mode 100644 index a52dc8f..0000000 --- a/lib/auth-configuration.js +++ /dev/null @@ -1,6 +0,0 @@ -export var AuthenticationType; -(function (AuthenticationType) { - AuthenticationType['Token'] = 'token'; - AuthenticationType['AuthorizationCode'] = 'code'; - AuthenticationType['IdToken'] = 'id_token'; -})(AuthenticationType || (AuthenticationType = {})); diff --git a/lib/auth-observer.d.ts b/lib/auth-observer.d.ts deleted file mode 100644 index ca77ffc..0000000 --- a/lib/auth-observer.d.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { IAuthAction } from './auth-action'; -import { TokenResponse } from '@openid/appauth'; -import { IAuthSession } from './auth-session'; -export declare abstract class BaseAuthObserver { - protected id: string; - abstract update(action: IAuthAction): void; -} -export declare class AuthObserver extends BaseAuthObserver { - private func; - constructor(func: (action: IAuthAction) => void); - update(action: IAuthAction): void; - static Create(func: (action: IAuthAction) => void): AuthObserver; -} -export declare class TokenObserver extends BaseAuthObserver { - token?: TokenResponse; - update(action: IAuthAction): void; -} -export declare class ActionHistoryObserver extends BaseAuthObserver { - history: IAuthAction[]; - lastAction?: IAuthAction; - update(action: IAuthAction): void; - clear(): void; -} -export declare class SessionObserver extends BaseAuthObserver { - session: IAuthSession; - update(action: IAuthAction): void; -} -export declare class ConsoleLogObserver extends BaseAuthObserver { - update(action: IAuthAction): void; -} diff --git a/lib/auth-observer.js b/lib/auth-observer.js deleted file mode 100644 index f563f5b..0000000 --- a/lib/auth-observer.js +++ /dev/null @@ -1,84 +0,0 @@ -import { AuthActions } from './auth-action'; -import { v4 as uuidv4 } from 'uuid'; -import { DefaultAuthSession } from './auth-session'; -export class BaseAuthObserver { - constructor() { - this.id = uuidv4(); - } -} -export class AuthObserver extends BaseAuthObserver { - constructor(func) { - super(); - this.func = func; - } - update(action) { - this.func(action); - } - static Create(func) { - return new AuthObserver(func); - } -} -export class TokenObserver extends BaseAuthObserver { - update(action) { - this.token = action.tokenResponse; - } -} -export class ActionHistoryObserver extends BaseAuthObserver { - constructor() { - super(...arguments); - this.history = []; - } - update(action) { - this.lastAction = action; - this.history.push(action); - } - clear() { - this.history = []; - this.lastAction = undefined; - } -} -export class SessionObserver extends BaseAuthObserver { - constructor() { - super(...arguments); - this.session = new DefaultAuthSession(); - } - update(action) { - switch (action.action) { - case AuthActions.SignInFailed: - case AuthActions.RefreshFailed: - case AuthActions.LoadTokenFromStorageFailed: - this.session.error = action.error; - this.session.token = undefined; - this.session.user = undefined; - this.session.isAuthenticated = false; - break; - case AuthActions.SignInSuccess: - case AuthActions.RefreshSuccess: - case AuthActions.LoadTokenFromStorageSuccess: - this.session.error = undefined; - this.session.token = action.tokenResponse; - this.session.isAuthenticated = true; - break; - case AuthActions.LoadUserInfoSuccess: - this.session.error = undefined; - this.session.user = action.user; - break; - case AuthActions.LoadUserInfoFailed: - this.session.error = action.error; - this.session.user = undefined; - break; - case AuthActions.SignOutSuccess: - case AuthActions.Init: - this.session = new DefaultAuthSession(); - break; - case AuthActions.SignOutFailed: - this.session.error = action.error; - break; - } - } -} -export class ConsoleLogObserver extends BaseAuthObserver { - update(action) { - console.log(action); - } -} diff --git a/lib/auth-service.d.ts b/lib/auth-service.d.ts deleted file mode 100644 index 881878b..0000000 --- a/lib/auth-service.d.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { AuthorizationRequestHandler, StringMap } from '@openid/appauth'; -import { IAuthAction } from './auth-action'; -import { UserInfoHandler } from './user-info-request-handler'; -import { EndSessionHandler } from './end-session-request-handler'; -import { IAuthConfig } from './auth-configuration'; -import { Browser } from './auth-browser'; -import { - StorageBackend, - Requestor, - AuthorizationServiceConfiguration, - TokenResponse, - AuthorizationRequest, - AuthorizationResponse, - AuthorizationError, - TokenRequestHandler, -} from '@openid/appauth'; -import { Observable } from 'rxjs'; -import { AuthObserver, BaseAuthObserver } from './auth-observer'; -export interface IAuthService { - signIn(authExtras?: StringMap, state?: string): void; - signOut(state?: string, revokeTokens?: boolean): void; - refreshToken(): void; - loadUserInfo(): void; - authorizationCallback(callbackUrl: string): void; - endSessionCallback(): void; - loadTokenFromStorage(): void; - getValidToken(buffer?: number): Promise; - addActionObserver(observer: BaseAuthObserver): void; - addActionListener(func: (action: IAuthAction) => void): AuthObserver; - removeActionObserver(observer: BaseAuthObserver): void; -} -export declare class AuthService implements IAuthService { - protected browser: Browser; - protected storage: StorageBackend; - protected requestor: Requestor; - private _configuration?; - private _authConfig?; - private _authSubject; - private _actionHistory; - private _session; - private _authSubjectV2; - private _tokenSubject; - private _userSubject; - private _authenticatedSubject; - private _initComplete; - protected tokenHandler: TokenRequestHandler; - protected userInfoHandler: UserInfoHandler; - protected requestHandler: AuthorizationRequestHandler; - protected endSessionHandler: EndSessionHandler; - constructor(browser?: Browser, storage?: StorageBackend, requestor?: Requestor); - /** - * @deprecated independant observers have been replaced by Rxjs - * this will be removed in a future release - * please use $ suffixed observers in future - */ - get history(): IAuthAction[]; - /** - * @deprecated independant observers have been replaced by Rxjs - * this will be removed in a future release - * please use $ suffixed observers in future - */ - get session(): import('./auth-session').IAuthSession; - get token$(): Observable; - get isAuthenticated$(): Observable; - get initComplete$(): Observable; - get user$(): Observable; - get events$(): Observable; - get authConfig(): IAuthConfig; - set authConfig(value: IAuthConfig); - get configuration(): Promise; - init(): Promise; - protected notifyActionListers(action: IAuthAction): void; - protected setupAuthorizationNotifier(): void; - protected onAuthorizationNotification( - request: AuthorizationRequest, - response: AuthorizationResponse | null, - error: AuthorizationError | null - ): void; - protected internalAuthorizationCallback(url: string): Promise; - protected internalEndSessionCallback(): Promise; - protected performEndSessionRequest(state?: string): Promise; - protected performAuthorizationRequest(authExtras?: StringMap, state?: string): Promise; - protected requestAccessToken(code: string, codeVerifier?: string): Promise; - protected requestTokenRefresh(): Promise; - protected internalLoadTokenFromStorage(): Promise; - protected requestTokenRevoke(): Promise; - protected internalRequestUserInfo(): Promise; - loadTokenFromStorage(): Promise; - signIn(authExtras?: StringMap, state?: string): Promise; - signOut(state?: string, revokeTokens?: boolean): Promise; - revokeTokens(): Promise; - refreshToken(): Promise; - loadUserInfo(): Promise; - authorizationCallback(callbackUrl: string): void; - endSessionCallback(): void; - getValidToken(buffer?: number): Promise; - /** - * @deprecated independant observers have been replaced by Rxjs - * this will be removed in a future release - * please use $ suffixed observers in future - */ - addActionListener(func: (action: IAuthAction) => void): AuthObserver; - /** - * @deprecated independant observers have been replaced by Rxjs - * this will be removed in a future release - * please use $ suffixed observers in future - */ - addActionObserver(observer: BaseAuthObserver): void; - /** - * @deprecated independant observers have been replaced by Rxjs - * this will be removed in a future release - * please use $ suffixed observers in future - */ - removeActionObserver(observer: BaseAuthObserver): void; -} diff --git a/lib/auth-service.js b/lib/auth-service.js deleted file mode 100644 index cfa7c77..0000000 --- a/lib/auth-service.js +++ /dev/null @@ -1,390 +0,0 @@ -import { __awaiter } from 'tslib'; -import { RevokeTokenRequest } from '@openid/appauth'; -import { AuthActionBuilder, AuthActions } from './auth-action'; -import { IonicUserInfoHandler } from './user-info-request-handler'; -import { IonicEndSessionHandler } from './end-session-request-handler'; -import { IonicAuthorizationRequestHandler, AUTHORIZATION_RESPONSE_KEY } from './authorization-request-handler'; -import { DefaultBrowser } from './auth-browser'; -import { - BaseTokenRequestHandler, - AuthorizationServiceConfiguration, - AuthorizationNotifier, - TokenResponse, - AuthorizationRequest, - DefaultCrypto, - GRANT_TYPE_AUTHORIZATION_CODE, - TokenRequest, - GRANT_TYPE_REFRESH_TOKEN, - LocalStorageBackend, - JQueryRequestor, -} from '@openid/appauth'; -import { EndSessionRequest } from './end-session-request'; -import { BehaviorSubject } from 'rxjs'; -import { ActionHistoryObserver, AuthObserver, SessionObserver } from './auth-observer'; -import { AuthSubject } from './auth-subject'; -const TOKEN_RESPONSE_KEY = 'token_response'; -const AUTH_EXPIRY_BUFFER = 10 * 60 * -1; // 10 mins in seconds -export class AuthService { - constructor(browser = new DefaultBrowser(), storage = new LocalStorageBackend(), requestor = new JQueryRequestor()) { - this.browser = browser; - this.storage = storage; - this.requestor = requestor; - this._authSubject = new AuthSubject(); - this._actionHistory = new ActionHistoryObserver(); - this._session = new SessionObserver(); - this._authSubjectV2 = new BehaviorSubject(AuthActionBuilder.Init()); - this._tokenSubject = new BehaviorSubject(undefined); - this._userSubject = new BehaviorSubject(undefined); - this._authenticatedSubject = new BehaviorSubject(false); - this._initComplete = new BehaviorSubject(false); - this.tokenHandler = new BaseTokenRequestHandler(requestor); - this.userInfoHandler = new IonicUserInfoHandler(requestor); - this.requestHandler = new IonicAuthorizationRequestHandler(browser, storage); - this.endSessionHandler = new IonicEndSessionHandler(browser); - } - /** - * @deprecated independant observers have been replaced by Rxjs - * this will be removed in a future release - * please use $ suffixed observers in future - */ - get history() { - return this._actionHistory.history.slice(0); - } - /** - * @deprecated independant observers have been replaced by Rxjs - * this will be removed in a future release - * please use $ suffixed observers in future - */ - get session() { - return this._session.session; - } - get token$() { - return this._tokenSubject.asObservable(); - } - get isAuthenticated$() { - return this._authenticatedSubject.asObservable(); - } - get initComplete$() { - return this._initComplete.asObservable(); - } - get user$() { - return this._userSubject.asObservable(); - } - get events$() { - return this._authSubjectV2.asObservable(); - } - get authConfig() { - if (!this._authConfig) throw new Error('AuthConfig Not Defined'); - return this._authConfig; - } - set authConfig(value) { - this._authConfig = value; - } - get configuration() { - if (!this._configuration) { - return AuthorizationServiceConfiguration.fetchFromIssuer(this.authConfig.server_host, this.requestor).catch(() => { - throw new Error('Unable To Obtain Server Configuration'); - }); - } - if (this._configuration != undefined) { - return Promise.resolve(this._configuration); - } else { - throw new Error('Unable To Obtain Server Configuration'); - } - } - init() { - return __awaiter(this, void 0, void 0, function* () { - this.setupAuthorizationNotifier(); - this.loadTokenFromStorage(); - this.addActionObserver(this._actionHistory); - this.addActionObserver(this._session); - }); - } - notifyActionListers(action) { - switch (action.action) { - case AuthActions.RefreshFailed: - case AuthActions.SignInFailed: - case AuthActions.SignOutSuccess: - case AuthActions.SignOutFailed: - this._tokenSubject.next(undefined); - this._userSubject.next(undefined); - this._authenticatedSubject.next(false); - break; - case AuthActions.LoadTokenFromStorageFailed: - this._tokenSubject.next(undefined); - this._userSubject.next(undefined); - this._authenticatedSubject.next(false); - this._initComplete.next(true); - break; - case AuthActions.SignInSuccess: - case AuthActions.RefreshSuccess: - this._tokenSubject.next(action.tokenResponse); - this._authenticatedSubject.next(true); - break; - case AuthActions.LoadTokenFromStorageSuccess: - this._tokenSubject.next(action.tokenResponse); - this._authenticatedSubject.next(action.tokenResponse.isValid(0)); - this._initComplete.next(true); - break; - case AuthActions.RevokeTokensSuccess: - this._tokenSubject.next(undefined); - break; - case AuthActions.LoadUserInfoSuccess: - this._userSubject.next(action.user); - break; - case AuthActions.LoadUserInfoFailed: - this._userSubject.next(undefined); - break; - } - this._authSubjectV2.next(action); - this._authSubject.notify(action); - } - setupAuthorizationNotifier() { - let notifier = new AuthorizationNotifier(); - this.requestHandler.setAuthorizationNotifier(notifier); - notifier.setAuthorizationListener((request, response, error) => this.onAuthorizationNotification(request, response, error)); - } - onAuthorizationNotification(request, response, error) { - let codeVerifier = request.internal != undefined && this.authConfig.pkce ? request.internal.code_verifier : undefined; - if (response != null) { - this.requestAccessToken(response.code, codeVerifier); - } else if (error != null) { - throw new Error(error.errorDescription); - } else { - throw new Error('Unknown Error With Authentication'); - } - } - internalAuthorizationCallback(url) { - return __awaiter(this, void 0, void 0, function* () { - this.browser.closeWindow(); - yield this.storage.setItem(AUTHORIZATION_RESPONSE_KEY, url); - return this.requestHandler.completeAuthorizationRequestIfPossible(); - }); - } - internalEndSessionCallback() { - return __awaiter(this, void 0, void 0, function* () { - this.browser.closeWindow(); - this._actionHistory.clear(); - this.notifyActionListers(AuthActionBuilder.SignOutSuccess()); - }); - } - performEndSessionRequest(state) { - return __awaiter(this, void 0, void 0, function* () { - if (this._tokenSubject.value != undefined) { - let requestJson = { - postLogoutRedirectURI: this.authConfig.end_session_redirect_url, - idTokenHint: this._tokenSubject.value.idToken || '', - state: state || undefined, - }; - let request = new EndSessionRequest(requestJson); - let returnedUrl = yield this.endSessionHandler.performEndSessionRequest(yield this.configuration, request); - //callback may come from showWindow or via another method - if (returnedUrl != undefined) { - this.endSessionCallback(); - } - } else { - //if user has no token they should not be logged in in the first place - this.endSessionCallback(); - } - }); - } - performAuthorizationRequest(authExtras, state) { - return __awaiter(this, void 0, void 0, function* () { - let requestJson = { - response_type: AuthorizationRequest.RESPONSE_TYPE_CODE, - client_id: this.authConfig.client_id, - redirect_uri: this.authConfig.redirect_url, - scope: this.authConfig.scopes, - extras: authExtras, - state: state || undefined, - }; - let request = new AuthorizationRequest(requestJson, new DefaultCrypto(), this.authConfig.pkce); - if (this.authConfig.pkce) yield request.setupCodeVerifier(); - return this.requestHandler.performAuthorizationRequest(yield this.configuration, request); - }); - } - requestAccessToken(code, codeVerifier) { - return __awaiter(this, void 0, void 0, function* () { - let requestJSON = { - grant_type: GRANT_TYPE_AUTHORIZATION_CODE, - code: code, - refresh_token: undefined, - redirect_uri: this.authConfig.redirect_url, - client_id: this.authConfig.client_id, - extras: codeVerifier - ? { - code_verifier: codeVerifier, - client_secret: this.authConfig.client_secret, - } - : { - client_secret: this.authConfig.client_secret, - }, - }; - let token = yield this.tokenHandler.performTokenRequest(yield this.configuration, new TokenRequest(requestJSON)); - yield this.storage.setItem(TOKEN_RESPONSE_KEY, JSON.stringify(token.toJson())); - this.notifyActionListers(AuthActionBuilder.SignInSuccess(token)); - }); - } - requestTokenRefresh() { - var _a; - return __awaiter(this, void 0, void 0, function* () { - if (!this._tokenSubject.value) { - throw new Error('No Token Defined!'); - } - let requestJSON = { - grant_type: GRANT_TYPE_REFRESH_TOKEN, - refresh_token: (_a = this._tokenSubject.value) === null || _a === void 0 ? void 0 : _a.refreshToken, - redirect_uri: this.authConfig.redirect_url, - client_id: this.authConfig.client_id, - }; - let token = yield this.tokenHandler.performTokenRequest(yield this.configuration, new TokenRequest(requestJSON)); - yield this.storage.setItem(TOKEN_RESPONSE_KEY, JSON.stringify(token.toJson())); - this.notifyActionListers(AuthActionBuilder.RefreshSuccess(token)); - }); - } - internalLoadTokenFromStorage() { - return __awaiter(this, void 0, void 0, function* () { - let token; - let tokenResponseString = yield this.storage.getItem(TOKEN_RESPONSE_KEY); - if (tokenResponseString != null) { - token = new TokenResponse(JSON.parse(tokenResponseString)); - if (token) { - return this.notifyActionListers(AuthActionBuilder.LoadTokenFromStorageSuccess(token)); - } - } - throw new Error('No Token In Storage'); - }); - } - requestTokenRevoke() { - return __awaiter(this, void 0, void 0, function* () { - let revokeRefreshJson = { - token: this._tokenSubject.value.refreshToken, - token_type_hint: 'refresh_token', - client_id: this.authConfig.client_id, - }; - let revokeAccessJson = { - token: this._tokenSubject.value.accessToken, - token_type_hint: 'access_token', - client_id: this.authConfig.client_id, - }; - yield this.tokenHandler.performRevokeTokenRequest(yield this.configuration, new RevokeTokenRequest(revokeRefreshJson)); - yield this.tokenHandler.performRevokeTokenRequest(yield this.configuration, new RevokeTokenRequest(revokeAccessJson)); - yield this.storage.removeItem(TOKEN_RESPONSE_KEY); - this.notifyActionListers(AuthActionBuilder.RevokeTokensSuccess()); - }); - } - internalRequestUserInfo() { - return __awaiter(this, void 0, void 0, function* () { - if (this._tokenSubject.value) { - let userInfo = yield this.userInfoHandler.performUserInfoRequest(yield this.configuration, this._tokenSubject.value); - this.notifyActionListers(AuthActionBuilder.LoadUserInfoSuccess(userInfo)); - } else { - throw new Error('No Token Available'); - } - }); - } - loadTokenFromStorage() { - return __awaiter(this, void 0, void 0, function* () { - yield this.internalLoadTokenFromStorage().catch((response) => { - this.notifyActionListers(AuthActionBuilder.LoadTokenFromStorageFailed(response)); - }); - }); - } - signIn(authExtras, state) { - return __awaiter(this, void 0, void 0, function* () { - yield this.performAuthorizationRequest(authExtras, state).catch((response) => { - this.notifyActionListers(AuthActionBuilder.SignInFailed(response)); - }); - }); - } - signOut(state, revokeTokens) { - return __awaiter(this, void 0, void 0, function* () { - if (revokeTokens) { - yield this.revokeTokens(); - } - yield this.storage.removeItem(TOKEN_RESPONSE_KEY); - if ((yield this.configuration).endSessionEndpoint) { - yield this.performEndSessionRequest(state).catch((response) => { - this.notifyActionListers(AuthActionBuilder.SignOutFailed(response)); - }); - } - }); - } - revokeTokens() { - return __awaiter(this, void 0, void 0, function* () { - yield this.requestTokenRevoke().catch((response) => { - this.storage.removeItem(TOKEN_RESPONSE_KEY); - this.notifyActionListers(AuthActionBuilder.RevokeTokensFailed(response)); - }); - }); - } - refreshToken() { - return __awaiter(this, void 0, void 0, function* () { - yield this.requestTokenRefresh().catch((response) => { - this.storage.removeItem(TOKEN_RESPONSE_KEY); - this.notifyActionListers(AuthActionBuilder.RefreshFailed(response)); - }); - }); - } - loadUserInfo() { - return __awaiter(this, void 0, void 0, function* () { - yield this.internalRequestUserInfo().catch((response) => { - this.notifyActionListers(AuthActionBuilder.LoadUserInfoFailed(response)); - }); - }); - } - authorizationCallback(callbackUrl) { - this.internalAuthorizationCallback(callbackUrl).catch((response) => { - this.notifyActionListers(AuthActionBuilder.SignInFailed(response)); - }); - } - endSessionCallback() { - this.internalEndSessionCallback().catch((response) => { - this.notifyActionListers(AuthActionBuilder.SignOutFailed(response)); - }); - } - getValidToken(buffer = AUTH_EXPIRY_BUFFER) { - return __awaiter(this, void 0, void 0, function* () { - if (this._tokenSubject.value) { - if (!this._tokenSubject.value.isValid(buffer)) { - yield this.refreshToken(); - if (this._tokenSubject.value) { - return this._tokenSubject.value; - } - } else { - return this._tokenSubject.value; - } - } - throw new Error('Unable To Obtain Valid Token'); - }); - } - /** - * @deprecated independant observers have been replaced by Rxjs - * this will be removed in a future release - * please use $ suffixed observers in future - */ - addActionListener(func) { - let observer = AuthObserver.Create(func); - this.addActionObserver(observer); - return observer; - } - /** - * @deprecated independant observers have been replaced by Rxjs - * this will be removed in a future release - * please use $ suffixed observers in future - */ - addActionObserver(observer) { - if (this._actionHistory.lastAction) { - observer.update(this._actionHistory.lastAction); - } - this._authSubject.attach(observer); - } - /** - * @deprecated independant observers have been replaced by Rxjs - * this will be removed in a future release - * please use $ suffixed observers in future - */ - removeActionObserver(observer) { - this._authSubject.detach(observer); - } -} diff --git a/lib/auth-session.d.ts b/lib/auth-session.d.ts deleted file mode 100644 index d2ab05f..0000000 --- a/lib/auth-session.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { TokenResponse } from '@openid/appauth'; -export interface IAuthSession { - isAuthenticated: boolean; - token?: TokenResponse; - user?: any; - error?: string; -} -export declare class DefaultAuthSession implements IAuthSession { - isAuthenticated: boolean; - token?: TokenResponse; - user?: any; - error?: string; -} diff --git a/lib/auth-session.js b/lib/auth-session.js deleted file mode 100644 index ef2634d..0000000 --- a/lib/auth-session.js +++ /dev/null @@ -1,8 +0,0 @@ -export class DefaultAuthSession { - constructor() { - this.isAuthenticated = false; - this.token = undefined; - this.user = undefined; - this.error = undefined; - } -} diff --git a/lib/auth-storage.d.ts b/lib/auth-storage.d.ts deleted file mode 100644 index 12b1e7d..0000000 --- a/lib/auth-storage.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { StorageBackend } from '@openid/appauth'; -import { Storage } from '@ionic/storage'; -export declare class IonicStorage implements StorageBackend { - store: Storage; - init: boolean; - getItem(name: string): Promise; - removeItem(name: string): Promise; - clear(): Promise; - setItem(name: string, value: string): Promise; -} diff --git a/lib/auth-storage.js b/lib/auth-storage.js deleted file mode 100644 index c67174a..0000000 --- a/lib/auth-storage.js +++ /dev/null @@ -1,44 +0,0 @@ -import { __awaiter } from 'tslib'; -import { Storage } from '@ionic/storage'; -export class IonicStorage { - constructor() { - this.store = new Storage(); - this.init = false; - } - getItem(name) { - return __awaiter(this, void 0, void 0, function* () { - if (!this.init) { - yield this.store.create(); - this.init = true; - } - return yield this.store.get(name); - }); - } - removeItem(name) { - return __awaiter(this, void 0, void 0, function* () { - if (!this.init) { - yield this.store.create(); - this.init = true; - } - return this.store.remove(name); - }); - } - clear() { - return __awaiter(this, void 0, void 0, function* () { - if (!this.init) { - yield this.store.create(); - this.init = true; - } - return this.store.clear(); - }); - } - setItem(name, value) { - return __awaiter(this, void 0, void 0, function* () { - if (!this.init) { - yield this.store.create(); - this.init = true; - } - return this.store.set(name, value); - }); - } -} diff --git a/lib/auth-subject.d.ts b/lib/auth-subject.d.ts deleted file mode 100644 index 6a479e5..0000000 --- a/lib/auth-subject.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { IAuthAction } from './auth-action'; -import { BaseAuthObserver } from './auth-observer'; -export interface IAuthSubject { - attach(observer: BaseAuthObserver): void; - detach(observer: BaseAuthObserver): void; - notify(action: IAuthAction): void; -} -export declare class AuthSubject implements IAuthSubject { - private observers; - attach(observer: BaseAuthObserver): void; - detach(observer: BaseAuthObserver): void; - notify(action: IAuthAction): void; -} diff --git a/lib/auth-subject.js b/lib/auth-subject.js deleted file mode 100644 index d65d164..0000000 --- a/lib/auth-subject.js +++ /dev/null @@ -1,24 +0,0 @@ -export class AuthSubject { - constructor() { - this.observers = []; - } - attach(observer) { - const observerIndex = this.observers.indexOf(observer); - if (observerIndex !== -1) { - return console.log('Subject: Observer has been attached already.'); - } - this.observers.push(observer); - } - detach(observer) { - const observerIndex = this.observers.indexOf(observer); - if (observerIndex === -1) { - return console.log('Subject: Nonexistent observer.'); - } - this.observers.splice(observerIndex, 1); - } - notify(action) { - for (const observer of this.observers) { - observer.update(action); - } - } -} diff --git a/lib/authorization-request-handler.d.ts b/lib/authorization-request-handler.d.ts deleted file mode 100644 index 9dc6d5e..0000000 --- a/lib/authorization-request-handler.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { - AuthorizationRequestHandler, - StorageBackend, - BasicQueryStringUtils, - DefaultCrypto, - AuthorizationServiceConfiguration, - AuthorizationRequest, - AuthorizationRequestResponse, -} from '@openid/appauth'; -import { Browser } from './auth-browser'; -export declare const AUTHORIZATION_RESPONSE_KEY = 'auth_response'; -export declare class IonicAuthorizationRequestHandler extends AuthorizationRequestHandler { - private browser; - private storage; - private generateRandom; - constructor(browser: Browser, storage: StorageBackend, utils?: BasicQueryStringUtils, generateRandom?: DefaultCrypto); - performAuthorizationRequest(configuration: AuthorizationServiceConfiguration, request: AuthorizationRequest): Promise; - protected completeAuthorizationRequest(): Promise; - private getAuthorizationRequest; - private getAuthorizationError; - private getAuthorizationResponse; - private removeItemsFromStorage; - private getQueryParams; -} diff --git a/lib/authorization-request-handler.js b/lib/authorization-request-handler.js deleted file mode 100644 index 74eed7a..0000000 --- a/lib/authorization-request-handler.js +++ /dev/null @@ -1,97 +0,0 @@ -import { __awaiter } from 'tslib'; -import { - AuthorizationRequestHandler, - BasicQueryStringUtils, - DefaultCrypto, - AuthorizationRequest, - AuthorizationError, - AuthorizationResponse, -} from '@openid/appauth'; -/** key for authorization request. */ -const authorizationRequestKey = (handle) => { - return `${handle}_appauth_authorization_request`; -}; -/** key in local storage which represents the current authorization request. */ -const AUTHORIZATION_REQUEST_HANDLE_KEY = 'appauth_current_authorization_request'; -export const AUTHORIZATION_RESPONSE_KEY = 'auth_response'; -export class IonicAuthorizationRequestHandler extends AuthorizationRequestHandler { - constructor(browser, storage, utils = new BasicQueryStringUtils(), generateRandom = new DefaultCrypto()) { - super(utils, generateRandom); - this.browser = browser; - this.storage = storage; - this.generateRandom = generateRandom; - } - performAuthorizationRequest(configuration, request) { - return __awaiter(this, void 0, void 0, function* () { - let handle = this.generateRandom.generateRandom(10); - yield this.storage.setItem(AUTHORIZATION_REQUEST_HANDLE_KEY, handle); - yield this.storage.setItem(authorizationRequestKey(handle), JSON.stringify(yield request.toJson())); - let url = this.buildRequestUrl(configuration, request); - let returnedUrl = yield this.browser.showWindow(url, request.redirectUri); - //callback may come from showWindow or via another method - if (returnedUrl != undefined) { - yield this.storage.setItem(AUTHORIZATION_RESPONSE_KEY, returnedUrl); - this.completeAuthorizationRequestIfPossible(); - } - }); - } - completeAuthorizationRequest() { - return __awaiter(this, void 0, void 0, function* () { - let handle = yield this.storage.getItem(AUTHORIZATION_REQUEST_HANDLE_KEY); - if (!handle) { - throw new Error('Handle Not Available'); - } - let request = this.getAuthorizationRequest(yield this.storage.getItem(authorizationRequestKey(handle))); - let queryParams = this.getQueryParams(yield this.storage.getItem(AUTHORIZATION_RESPONSE_KEY)); - this.removeItemsFromStorage(handle); - let state = queryParams['state']; - let error = queryParams['error']; - if (state !== request.state) { - throw new Error('State Does Not Match'); - } - return { - request: request, - response: !error ? this.getAuthorizationResponse(queryParams) : undefined, - error: error ? this.getAuthorizationError(queryParams) : undefined, - }; - }); - } - getAuthorizationRequest(authRequest) { - if (authRequest == null) { - throw new Error('No Auth Request Available'); - } - return new AuthorizationRequest(JSON.parse(authRequest)); - } - getAuthorizationError(queryParams) { - let authorizationErrorJSON = { - error: queryParams['error'], - error_description: queryParams['error_description'], - error_uri: undefined, - state: queryParams['state'], - }; - return new AuthorizationError(authorizationErrorJSON); - } - getAuthorizationResponse(queryParams) { - let authorizationResponseJSON = { - code: queryParams['code'], - state: queryParams['state'], - }; - return new AuthorizationResponse(authorizationResponseJSON); - } - removeItemsFromStorage(handle) { - this.storage.removeItem(AUTHORIZATION_REQUEST_HANDLE_KEY); - this.storage.removeItem(authorizationRequestKey(handle)); - this.storage.removeItem(AUTHORIZATION_RESPONSE_KEY); - } - getQueryParams(authResponse) { - if (authResponse != null) { - let querySide = authResponse.split('#')[0]; - let parts = querySide.split('?'); - if (parts.length !== 2) throw new Error('Invalid auth response string'); - let hash = parts[1]; - return this.utils.parseQueryString(hash); - } else { - return {}; - } - } -} diff --git a/lib/capacitor/capacitor-browser.d.ts b/lib/capacitor/capacitor-browser.d.ts deleted file mode 100644 index dd63446..0000000 --- a/lib/capacitor/capacitor-browser.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Browser } from '../auth-browser'; -export declare class CapacitorBrowser extends Browser { - closeWindow(): void | Promise; - showWindow(url: string): Promise; -} diff --git a/lib/capacitor/capacitor-browser.js b/lib/capacitor/capacitor-browser.js deleted file mode 100644 index b9f1a52..0000000 --- a/lib/capacitor/capacitor-browser.js +++ /dev/null @@ -1,26 +0,0 @@ -import { __awaiter } from 'tslib'; -import { Browser } from '../auth-browser'; -import { Browser as CapBrowser } from '@capacitor/browser'; -import { Capacitor } from '@capacitor/core'; -export class CapacitorBrowser extends Browser { - closeWindow() { - if (!CapBrowser) throw new Error('Capacitor Browser Is Undefined!'); - if (Capacitor.getPlatform() !== 'android') { - CapBrowser.close(); - } - } - showWindow(url) { - return __awaiter(this, void 0, void 0, function* () { - const options = { - url: url, - windowName: '_self', - }; - if (!CapBrowser) throw new Error('Capacitor Browser Is Undefined!'); - CapBrowser.addListener('browserFinished', () => { - this.onCloseFunction(); - }); - CapBrowser.open(options); - return; - }); - } -} diff --git a/lib/capacitor/capacitor-secure-storage.d.ts b/lib/capacitor/capacitor-secure-storage.d.ts deleted file mode 100644 index 0e2577e..0000000 --- a/lib/capacitor/capacitor-secure-storage.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { StorageBackend } from '@openid/appauth'; -export declare class CapacitorSecureStorage implements StorageBackend { - getItem(name: string): Promise; - removeItem(name: string): Promise; - clear(): Promise; - setItem(name: string, value: string): Promise; -} diff --git a/lib/capacitor/capacitor-secure-storage.js b/lib/capacitor/capacitor-secure-storage.js deleted file mode 100644 index 7ce3b94..0000000 --- a/lib/capacitor/capacitor-secure-storage.js +++ /dev/null @@ -1,36 +0,0 @@ -import { __awaiter } from 'tslib'; -import { SecureStoragePlugin } from 'capacitor-secure-storage-plugin'; -// REQUIRES CAPACITOR PLUGINS -// capacitor-secure-storage-plugin -export class CapacitorSecureStorage { - getItem(name) { - return __awaiter(this, void 0, void 0, function* () { - if (!SecureStoragePlugin) throw new Error('Capacitor Secure Storage Is Undefined!'); - const returned = yield SecureStoragePlugin.get({ - key: name, - }).catch(() => { - return { - value: null, - }; - }); - return returned.value; - }); - } - removeItem(name) { - if (!SecureStoragePlugin) throw new Error('Capacitor Secure Storage Is Undefined!'); - return SecureStoragePlugin.remove({ - key: name, - }).then(() => {}); - } - clear() { - if (!SecureStoragePlugin) throw new Error('Capacitor Secure Storage Is Undefined!'); - return SecureStoragePlugin.clear().then(() => {}); - } - setItem(name, value) { - if (!SecureStoragePlugin) throw new Error('Capacitor Secure Storage Is Undefined!'); - return SecureStoragePlugin.set({ - key: name, - value: value, - }).then(() => {}); - } -} diff --git a/lib/capacitor/capacitor-storage.d.ts b/lib/capacitor/capacitor-storage.d.ts deleted file mode 100644 index d625d03..0000000 --- a/lib/capacitor/capacitor-storage.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { StorageBackend } from '@openid/appauth'; -export declare class CapacitorStorage implements StorageBackend { - getItem(name: string): Promise; - removeItem(name: string): Promise; - clear(): Promise; - setItem(name: string, value: string): Promise; -} diff --git a/lib/capacitor/capacitor-storage.js b/lib/capacitor/capacitor-storage.js deleted file mode 100644 index e924113..0000000 --- a/lib/capacitor/capacitor-storage.js +++ /dev/null @@ -1,30 +0,0 @@ -import { __awaiter } from 'tslib'; -import { Preferences } from '@capacitor/preferences'; -export class CapacitorStorage { - getItem(name) { - return __awaiter(this, void 0, void 0, function* () { - if (!Preferences) throw new Error('Capacitor Preferences Is Undefined!'); - const returned = yield Preferences.get({ - key: name, - }); - return returned.value; - }); - } - removeItem(name) { - if (!Preferences) throw new Error('Capacitor Preferences Is Undefined!'); - return Preferences.remove({ - key: name, - }); - } - clear() { - if (!Preferences) throw new Error('Capacitor Preferences Is Undefined!'); - return Preferences.clear(); - } - setItem(name, value) { - if (!Preferences) throw new Error('Capacitor Preferences Is Undefined!'); - return Preferences.set({ - key: name, - value: value, - }); - } -} diff --git a/lib/capacitor/index.d.ts b/lib/capacitor/index.d.ts deleted file mode 100644 index 6209866..0000000 --- a/lib/capacitor/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './capacitor-browser'; -export * from './capacitor-storage'; -export * from './capacitor-secure-storage'; diff --git a/lib/capacitor/index.js b/lib/capacitor/index.js deleted file mode 100644 index 6209866..0000000 --- a/lib/capacitor/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './capacitor-browser'; -export * from './capacitor-storage'; -export * from './capacitor-secure-storage'; diff --git a/lib/cordova/cordova-browser.d.ts b/lib/cordova/cordova-browser.d.ts deleted file mode 100644 index 1eca863..0000000 --- a/lib/cordova/cordova-browser.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Browser } from '../auth-browser'; -export declare class CordovaBrowser extends Browser { - private inAppBrowserRef; - closeWindow(): Promise; - showWindow(url: string): Promise; -} diff --git a/lib/cordova/cordova-browser.js b/lib/cordova/cordova-browser.js deleted file mode 100644 index b2fd38a..0000000 --- a/lib/cordova/cordova-browser.js +++ /dev/null @@ -1,50 +0,0 @@ -import { __awaiter } from 'tslib'; -import { CordovaDocument } from './cordova-document'; -import { Browser } from '../auth-browser'; -import { SafariViewController } from '@awesome-cordova-plugins/safari-view-controller'; -import { InAppBrowser } from '@awesome-cordova-plugins/in-app-browser'; -// REQUIRES CORDOVA PLUGINS -// cordova-plugin-safariviewcontroller -// cordova-plugin-customurlscheme -// cordova-plugin-inappbrowser FROM https://github.com/Onegini/cordova-plugin-inappbrowser.git -export class CordovaBrowser extends Browser { - closeWindow() { - return __awaiter(this, void 0, void 0, function* () { - yield CordovaDocument.ready(); - if (yield SafariViewController.isAvailable()) { - try { - SafariViewController.hide(); - } catch (_a) {} - } else { - if (this.inAppBrowserRef != undefined) this.inAppBrowserRef.close(); - } - }); - } - showWindow(url) { - return __awaiter(this, void 0, void 0, function* () { - yield CordovaDocument.ready(); - if (yield SafariViewController.isAvailable()) { - let optionSafari = { - url: url, - showDefaultShareMenuItem: false, - toolbarColor: '#ffffff', - }; - SafariViewController.show(optionSafari).subscribe((result) => { - if (result.event === 'closed') { - this.onCloseFunction(); - } - }); - } else { - let options = { - location: 'no', - zoom: 'no', - clearcache: 'yes', - clearsessioncache: 'yes', - }; - this.inAppBrowserRef = InAppBrowser.create(url, '_self', options); - if (this.inAppBrowserRef != undefined) this.inAppBrowserRef.on('exit').subscribe(() => this.onCloseFunction()); - } - return; - }); - } -} diff --git a/lib/cordova/cordova-document.d.ts b/lib/cordova/cordova-document.d.ts deleted file mode 100644 index 625a5d4..0000000 --- a/lib/cordova/cordova-document.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export declare class CordovaDocument { - static ready(f?: Function): Promise; -} diff --git a/lib/cordova/cordova-document.js b/lib/cordova/cordova-document.js deleted file mode 100644 index 3a23aba..0000000 --- a/lib/cordova/cordova-document.js +++ /dev/null @@ -1,12 +0,0 @@ -export class CordovaDocument { - static ready(f) { - return new Promise((resolve) => { - document.addEventListener('deviceready', () => { - if (f != undefined) { - f(); - } - resolve(); - }); - }); - } -} diff --git a/lib/cordova/cordova-requestor.d.ts b/lib/cordova/cordova-requestor.d.ts deleted file mode 100644 index 52f0481..0000000 --- a/lib/cordova/cordova-requestor.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Requestor } from '@openid/appauth'; -export interface XhrSettings { - url: string; - dataType?: string; - method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; - data?: any; - headers?: any; -} -export declare class CordovaRequestor extends Requestor { - constructor(); - xhr(settings: XhrSettings): Promise; - private makeRequest; - private get; - private post; - private put; - private delete; -} diff --git a/lib/cordova/cordova-requestor.js b/lib/cordova/cordova-requestor.js deleted file mode 100644 index 841d9a6..0000000 --- a/lib/cordova/cordova-requestor.js +++ /dev/null @@ -1,56 +0,0 @@ -import { __awaiter } from 'tslib'; -import { CordovaDocument } from './cordova-document'; -import { Requestor } from '@openid/appauth'; -import { HTTP } from '@awesome-cordova-plugins/http'; -// REQUIRES CORDOVA PLUGINS -// cordova-plugin-advanced-http -export class CordovaRequestor extends Requestor { - constructor() { - super(); - } - xhr(settings) { - return __awaiter(this, void 0, void 0, function* () { - if (!settings.method) settings.method = 'GET'; - yield CordovaDocument.ready(); - const previousSerializerType = HTTP.getDataSerializer(); - HTTP.setDataSerializer('utf8'); - const response = yield this.makeRequest(settings); - HTTP.setDataSerializer(previousSerializerType); - return response; - }); - } - makeRequest(settings) { - return __awaiter(this, void 0, void 0, function* () { - switch (settings.method) { - case 'GET': - return this.get(settings.url, settings.headers); - case 'POST': - return this.post(settings.url, settings.data, settings.headers); - case 'PUT': - return this.put(settings.url, settings.data, settings.headers); - case 'DELETE': - return this.delete(settings.url, settings.headers); - } - }); - } - get(url, headers) { - return __awaiter(this, void 0, void 0, function* () { - return HTTP.get(url, undefined, headers).then((response) => JSON.parse(response.data)); - }); - } - post(url, data, headers) { - return __awaiter(this, void 0, void 0, function* () { - return HTTP.post(url, data, headers).then((response) => JSON.parse(response.data)); - }); - } - put(url, data, headers) { - return __awaiter(this, void 0, void 0, function* () { - return HTTP.put(url, data, headers).then((response) => JSON.parse(response.data)); - }); - } - delete(url, headers) { - return __awaiter(this, void 0, void 0, function* () { - return HTTP.delete(url, undefined, headers).then((response) => JSON.parse(response.data)); - }); - } -} diff --git a/lib/cordova/cordova-secure-storage.d.ts b/lib/cordova/cordova-secure-storage.d.ts deleted file mode 100644 index 49503cf..0000000 --- a/lib/cordova/cordova-secure-storage.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { StorageBackend } from '@openid/appauth'; -import { SecureStorageObject } from '@awesome-cordova-plugins/secure-storage'; -export declare class CordovaSecureStorage extends StorageBackend { - private localData; - private KEYSTORE; - SecureStorageExists(): Promise; - hasRecord(store: SecureStorageObject, key: string): Promise; - getItem(name: string): Promise; - removeItem(name: string): Promise; - setItem(name: string, value: string): Promise; - clear(): Promise; - private getTemp; - private setTemp; - private removeTemp; - private clearTemp; -} diff --git a/lib/cordova/cordova-secure-storage.js b/lib/cordova/cordova-secure-storage.js deleted file mode 100644 index 9f3de49..0000000 --- a/lib/cordova/cordova-secure-storage.js +++ /dev/null @@ -1,91 +0,0 @@ -import { __awaiter } from 'tslib'; -import { CordovaDocument } from './cordova-document'; -import { StorageBackend } from '@openid/appauth'; -import { SecureStorage } from '@awesome-cordova-plugins/secure-storage'; -// REQUIRES CORDOVA PLUGINS -// cordova-plugin-secure-storage -export class CordovaSecureStorage extends StorageBackend { - constructor() { - super(...arguments); - this.localData = {}; - this.KEYSTORE = 'SecretStore'; - } - SecureStorageExists() { - return __awaiter(this, void 0, void 0, function* () { - yield CordovaDocument.ready(); - return SecureStorage.create(this.KEYSTORE).then( - () => true, - () => false - ); - }); - } - hasRecord(store, key) { - return __awaiter(this, void 0, void 0, function* () { - let keys = yield store.keys(); - return keys.indexOf(key) > -1; - }); - } - getItem(name) { - return __awaiter(this, void 0, void 0, function* () { - yield CordovaDocument.ready(); - return SecureStorage.create(this.KEYSTORE) - .then((store) => { - return store.get(name).catch(() => null); - }) - .catch(() => { - return this.getTemp(name); - }); - }); - } - removeItem(name) { - return __awaiter(this, void 0, void 0, function* () { - yield CordovaDocument.ready(); - return SecureStorage.create(this.KEYSTORE) - .then((store) => { - store.remove(name); - }) - .catch(() => { - this.removeTemp(name); - }); - }); - } - setItem(name, value) { - return __awaiter(this, void 0, void 0, function* () { - yield CordovaDocument.ready(); - return SecureStorage.create(this.KEYSTORE) - .then((store) => { - store.set(name, value); - }) - .catch(() => { - this.setTemp(name, value); - }); - }); - } - clear() { - return __awaiter(this, void 0, void 0, function* () { - yield CordovaDocument.ready(); - return SecureStorage.create(this.KEYSTORE) - .then((store) => { - store.clear(); - }) - .catch(() => { - this.clearTemp(); - }); - }); - } - getTemp(key) { - if (this.localData[key]) return this.localData[key]; - else return null; - } - setTemp(key, data) { - this.localData[key] = data; - } - removeTemp(key) { - if (this.localData[key]) { - delete this.localData[key]; - } - } - clearTemp() { - this.localData = {}; - } -} diff --git a/lib/cordova/index.d.ts b/lib/cordova/index.d.ts deleted file mode 100644 index d66733e..0000000 --- a/lib/cordova/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './cordova-browser'; -export * from './cordova-secure-storage'; -export * from './cordova-requestor'; diff --git a/lib/cordova/index.js b/lib/cordova/index.js deleted file mode 100644 index d66733e..0000000 --- a/lib/cordova/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './cordova-browser'; -export * from './cordova-secure-storage'; -export * from './cordova-requestor'; diff --git a/lib/end-session-request-handler.d.ts b/lib/end-session-request-handler.d.ts deleted file mode 100644 index 10b2d3e..0000000 --- a/lib/end-session-request-handler.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { EndSessionRequest } from './end-session-request'; -import { AuthorizationServiceConfiguration, BasicQueryStringUtils } from '@openid/appauth'; -import { Browser } from './auth-browser'; -export interface EndSessionHandler { - performEndSessionRequest(configuration: AuthorizationServiceConfiguration, request: EndSessionRequest): Promise; -} -export declare class IonicEndSessionHandler implements EndSessionHandler { - private browser; - private utils; - constructor(browser: Browser, utils?: BasicQueryStringUtils); - performEndSessionRequest(configuration: AuthorizationServiceConfiguration, request: EndSessionRequest): Promise; - private buildRequestUrl; -} diff --git a/lib/end-session-request-handler.js b/lib/end-session-request-handler.js deleted file mode 100644 index 7a95f9c..0000000 --- a/lib/end-session-request-handler.js +++ /dev/null @@ -1,25 +0,0 @@ -import { __awaiter } from 'tslib'; -import { BasicQueryStringUtils } from '@openid/appauth'; -export class IonicEndSessionHandler { - constructor(browser, utils = new BasicQueryStringUtils()) { - this.browser = browser; - this.utils = utils; - } - performEndSessionRequest(configuration, request) { - return __awaiter(this, void 0, void 0, function* () { - let url = this.buildRequestUrl(configuration, request); - return this.browser.showWindow(url, request.postLogoutRedirectURI); - }); - } - buildRequestUrl(configuration, request) { - let requestMap = { - id_token_hint: request.idTokenHint, - post_logout_redirect_uri: request.postLogoutRedirectURI, - state: request.state, - }; - let query = this.utils.stringify(requestMap); - let baseUrl = configuration.endSessionEndpoint; - let url = `${baseUrl}?${query}`; - return url; - } -} diff --git a/lib/end-session-request.d.ts b/lib/end-session-request.d.ts deleted file mode 100644 index 69edafa..0000000 --- a/lib/end-session-request.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Crypto } from '@openid/appauth/built/crypto_utils'; -export interface EndSessionRequestJson { - idTokenHint: string; - postLogoutRedirectURI: string; - state?: string; -} -export declare class EndSessionRequest { - state: string; - idTokenHint: string; - postLogoutRedirectURI: string; - constructor(request: EndSessionRequestJson, crypto?: Crypto); - toJson(): EndSessionRequestJson; -} diff --git a/lib/end-session-request.js b/lib/end-session-request.js deleted file mode 100644 index e2ebb55..0000000 --- a/lib/end-session-request.js +++ /dev/null @@ -1,22 +0,0 @@ -import { DefaultCrypto } from '@openid/appauth/built/crypto_utils'; -const BYTES_LENGTH = 10; -const newState = function (crypto) { - return crypto.generateRandom(BYTES_LENGTH); -}; -export class EndSessionRequest { - constructor(request, crypto = new DefaultCrypto()) { - this.state = request.state || newState(crypto); - this.idTokenHint = request.idTokenHint; - this.postLogoutRedirectURI = request.postLogoutRedirectURI; - } - toJson() { - let json = { - idTokenHint: this.idTokenHint, - postLogoutRedirectURI: this.postLogoutRedirectURI, - }; - if (this.state) { - json['state'] = this.state; - } - return json; - } -} diff --git a/lib/index.d.ts b/lib/index.d.ts deleted file mode 100644 index ade60c5..0000000 --- a/lib/index.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -export * from './auth-browser'; -export * from './auth-configuration'; -export * from './authorization-request-handler'; -export * from './end-session-request'; -export * from './end-session-request-handler'; -export * from './auth-service'; -export * from './auth-action'; -export * from './user-info-request-handler'; -export * from './auth-observer'; -export * from './auth-subject'; -export * from './auth-storage'; diff --git a/lib/index.js b/lib/index.js deleted file mode 100644 index ade60c5..0000000 --- a/lib/index.js +++ /dev/null @@ -1,11 +0,0 @@ -export * from './auth-browser'; -export * from './auth-configuration'; -export * from './authorization-request-handler'; -export * from './end-session-request'; -export * from './end-session-request-handler'; -export * from './auth-service'; -export * from './auth-action'; -export * from './user-info-request-handler'; -export * from './auth-observer'; -export * from './auth-subject'; -export * from './auth-storage'; diff --git a/lib/user-info-request-handler.d.ts b/lib/user-info-request-handler.d.ts deleted file mode 100644 index 7b18613..0000000 --- a/lib/user-info-request-handler.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { AuthorizationServiceConfiguration, TokenResponse, Requestor } from '@openid/appauth'; -export interface UserInfoHandler { - performUserInfoRequest(configuration: AuthorizationServiceConfiguration, token: TokenResponse): Promise; -} -export declare class IonicUserInfoHandler implements UserInfoHandler { - private requestor; - constructor(requestor: Requestor); - performUserInfoRequest(configuration: AuthorizationServiceConfiguration, token: TokenResponse): Promise; -} diff --git a/lib/user-info-request-handler.js b/lib/user-info-request-handler.js deleted file mode 100644 index ff4a77f..0000000 --- a/lib/user-info-request-handler.js +++ /dev/null @@ -1,20 +0,0 @@ -import { __awaiter } from 'tslib'; -export class IonicUserInfoHandler { - constructor(requestor) { - this.requestor = requestor; - } - performUserInfoRequest(configuration, token) { - return __awaiter(this, void 0, void 0, function* () { - let settings = { - url: configuration.userInfoEndpoint, - dataType: 'json', - method: 'GET', - headers: { - Authorization: `${token.tokenType == 'bearer' ? 'Bearer' : token.tokenType} ${token.accessToken}`, - 'Content-Type': 'application/json', - }, - }; - return this.requestor.xhr(settings); - }); - } -} diff --git a/package.json b/package.json index 6bf5bd7..e53651d 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "test": "mocha --config test/runners/mocha/.mocharc.jsonc", "test:coverage": "nyc npm run test", "build": "tsc", - "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\" \"lib/**/*.*\"", + "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "lint": "eslint . --ext .ts", "prepare": "husky install", "prepublishOnly": "npm run build" @@ -87,4 +87,4 @@ "@ionic/storage": "^4.0.0", "capacitor-secure-storage-plugin": "^0.9.0" } -} +} \ No newline at end of file diff --git a/src/auth-service.ts b/src/auth-service.ts index c887020..231de33 100644 --- a/src/auth-service.ts +++ b/src/auth-service.ts @@ -1,34 +1,40 @@ -import { AuthorizationRequestHandler, RevokeTokenRequest, RevokeTokenRequestJson, StringMap } from '@openid/appauth'; -import { IAuthAction, AuthActionBuilder, AuthActions } from './auth-action'; -import { IonicUserInfoHandler, UserInfoHandler } from './user-info-request-handler'; -import { IonicEndSessionHandler, EndSessionHandler } from './end-session-request-handler'; -import { IAuthConfig } from './auth-configuration'; -import { IonicAuthorizationRequestHandler, AUTHORIZATION_RESPONSE_KEY } from './authorization-request-handler'; -import { Browser, DefaultBrowser } from './auth-browser'; +import { BehaviorSubject, Observable } from 'rxjs'; + +import type { Crypto } from '@openid/appauth'; import { - StorageBackend, - Requestor, - BaseTokenRequestHandler, - AuthorizationServiceConfiguration, + AuthorizationError, AuthorizationNotifier, - TokenResponse, - AuthorizationRequestJson, AuthorizationRequest, + AuthorizationRequestHandler, + AuthorizationRequestJson, + AuthorizationResponse, + AuthorizationServiceConfiguration, + BaseTokenRequestHandler, DefaultCrypto, GRANT_TYPE_AUTHORIZATION_CODE, - TokenRequestJson, - TokenRequest, GRANT_TYPE_REFRESH_TOKEN, - AuthorizationResponse, - AuthorizationError, - LocalStorageBackend, JQueryRequestor, + LocalStorageBackend, + Requestor, + RevokeTokenRequest, + RevokeTokenRequestJson, + StorageBackend, + StringMap, + TokenRequest, TokenRequestHandler, + TokenRequestJson, + TokenResponse, } from '@openid/appauth'; -import { EndSessionRequestJson, EndSessionRequest } from './end-session-request'; -import { BehaviorSubject, Observable } from 'rxjs'; + +import { AuthActionBuilder, AuthActions, IAuthAction } from './auth-action'; +import { Browser, DefaultBrowser } from './auth-browser'; +import { IAuthConfig } from './auth-configuration'; import { ActionHistoryObserver, AuthObserver, BaseAuthObserver, SessionObserver } from './auth-observer'; import { AuthSubject } from './auth-subject'; +import { AUTHORIZATION_RESPONSE_KEY, IonicAuthorizationRequestHandler } from './authorization-request-handler'; +import { EndSessionRequest, EndSessionRequestJson } from './end-session-request'; +import { EndSessionHandler, IonicEndSessionHandler } from './end-session-request-handler'; +import { IonicUserInfoHandler, UserInfoHandler } from './user-info-request-handler'; const TOKEN_RESPONSE_KEY = 'token_response'; const AUTH_EXPIRY_BUFFER = 10 * 60 * -1; // 10 mins in seconds @@ -69,11 +75,12 @@ export class AuthService implements IAuthService { constructor( protected browser: Browser = new DefaultBrowser(), protected storage: StorageBackend = new LocalStorageBackend(), - protected requestor: Requestor = new JQueryRequestor() + protected requestor: Requestor = new JQueryRequestor(), + protected crypto: Crypto = new DefaultCrypto(), ) { this.tokenHandler = new BaseTokenRequestHandler(requestor); this.userInfoHandler = new IonicUserInfoHandler(requestor); - this.requestHandler = new IonicAuthorizationRequestHandler(browser, storage); + this.requestHandler = new IonicAuthorizationRequestHandler(browser, storage, crypto); this.endSessionHandler = new IonicEndSessionHandler(browser); } @@ -188,7 +195,7 @@ export class AuthService implements IAuthService { } protected setupAuthorizationNotifier() { - let notifier = new AuthorizationNotifier(); + const notifier = new AuthorizationNotifier(); this.requestHandler.setAuthorizationNotifier(notifier); notifier.setAuthorizationListener((request, response, error) => this.onAuthorizationNotification(request, response, error)); } @@ -196,9 +203,9 @@ export class AuthService implements IAuthService { protected onAuthorizationNotification( request: AuthorizationRequest, response: AuthorizationResponse | null, - error: AuthorizationError | null + error: AuthorizationError | null, ) { - let codeVerifier: string | undefined = + const codeVerifier: string | undefined = request.internal != undefined && this.authConfig.pkce ? request.internal.code_verifier : undefined; if (response != null) { @@ -223,24 +230,22 @@ export class AuthService implements IAuthService { } protected async performEndSessionRequest(state?: string): Promise { - - let requestJson: EndSessionRequestJson = { + const requestJson: EndSessionRequestJson = { postLogoutRedirectURI: this.authConfig.end_session_redirect_url, idTokenHint: this._tokenSubject.value ? this._tokenSubject.value.idToken || '' : '', state: state || undefined, }; - let request: EndSessionRequest = new EndSessionRequest(requestJson); - let returnedUrl: string | undefined = await this.endSessionHandler.performEndSessionRequest(await this.configuration, request); + const request: EndSessionRequest = new EndSessionRequest(requestJson, this.crypto); + const returnedUrl: string | undefined = await this.endSessionHandler.performEndSessionRequest(await this.configuration, request); //callback may come from showWindow or via another method if (returnedUrl != undefined) { this.endSessionCallback(); } - } protected async performAuthorizationRequest(authExtras?: StringMap, state?: string): Promise { - let requestJson: AuthorizationRequestJson = { + const requestJson: AuthorizationRequestJson = { response_type: AuthorizationRequest.RESPONSE_TYPE_CODE, client_id: this.authConfig.client_id, redirect_uri: this.authConfig.redirect_url, @@ -249,14 +254,14 @@ export class AuthService implements IAuthService { state: state || undefined, }; - let request = new AuthorizationRequest(requestJson, new DefaultCrypto(), this.authConfig.pkce); + const request = new AuthorizationRequest(requestJson, this.crypto, this.authConfig.pkce); if (this.authConfig.pkce) await request.setupCodeVerifier(); return this.requestHandler.performAuthorizationRequest(await this.configuration, request); } protected async requestAccessToken(code: string, codeVerifier?: string): Promise { - let requestJSON: TokenRequestJson = { + const requestJSON: TokenRequestJson = { grant_type: GRANT_TYPE_AUTHORIZATION_CODE, code: code, refresh_token: undefined, @@ -272,7 +277,7 @@ export class AuthService implements IAuthService { }, }; - let token: TokenResponse = await this.tokenHandler.performTokenRequest(await this.configuration, new TokenRequest(requestJSON)); + const token: TokenResponse = await this.tokenHandler.performTokenRequest(await this.configuration, new TokenRequest(requestJSON)); await this.storage.setItem(TOKEN_RESPONSE_KEY, JSON.stringify(token.toJson())); this.notifyActionListers(AuthActionBuilder.SignInSuccess(token)); } @@ -282,21 +287,21 @@ export class AuthService implements IAuthService { throw new Error('No Token Defined!'); } - let requestJSON: TokenRequestJson = { + const requestJSON: TokenRequestJson = { grant_type: GRANT_TYPE_REFRESH_TOKEN, refresh_token: this._tokenSubject.value?.refreshToken, redirect_uri: this.authConfig.redirect_url, client_id: this.authConfig.client_id, }; - let token: TokenResponse = await this.tokenHandler.performTokenRequest(await this.configuration, new TokenRequest(requestJSON)); + const token: TokenResponse = await this.tokenHandler.performTokenRequest(await this.configuration, new TokenRequest(requestJSON)); await this.storage.setItem(TOKEN_RESPONSE_KEY, JSON.stringify(token.toJson())); this.notifyActionListers(AuthActionBuilder.RefreshSuccess(token)); } protected async internalLoadTokenFromStorage() { let token: TokenResponse | undefined; - let tokenResponseString: string | null = await this.storage.getItem(TOKEN_RESPONSE_KEY); + const tokenResponseString: string | null = await this.storage.getItem(TOKEN_RESPONSE_KEY); if (tokenResponseString != null) { token = new TokenResponse(JSON.parse(tokenResponseString)); @@ -310,13 +315,13 @@ export class AuthService implements IAuthService { } protected async requestTokenRevoke() { - let revokeRefreshJson: RevokeTokenRequestJson = { + const revokeRefreshJson: RevokeTokenRequestJson = { token: this._tokenSubject.value.refreshToken, token_type_hint: 'refresh_token', client_id: this.authConfig.client_id, }; - let revokeAccessJson: RevokeTokenRequestJson = { + const revokeAccessJson: RevokeTokenRequestJson = { token: this._tokenSubject.value.accessToken, token_type_hint: 'access_token', client_id: this.authConfig.client_id, @@ -330,7 +335,7 @@ export class AuthService implements IAuthService { protected async internalRequestUserInfo() { if (this._tokenSubject.value) { - let userInfo = await this.userInfoHandler.performUserInfoRequest(await this.configuration, this._tokenSubject.value); + const userInfo = await this.userInfoHandler.performUserInfoRequest(await this.configuration, this._tokenSubject.value); this.notifyActionListers(AuthActionBuilder.LoadUserInfoSuccess(userInfo)); } else { throw new Error('No Token Available'); @@ -350,7 +355,6 @@ export class AuthService implements IAuthService { } public async signOut(state?: string, revokeTokens?: boolean) { - if (revokeTokens) { await this.revokeTokens(); } @@ -420,7 +424,7 @@ export class AuthService implements IAuthService { * please use $ suffixed observers in future */ public addActionListener(func: (action: IAuthAction) => void): AuthObserver { - let observer: AuthObserver = AuthObserver.Create(func); + const observer: AuthObserver = AuthObserver.Create(func); this.addActionObserver(observer); return observer; } diff --git a/src/authorization-request-handler.ts b/src/authorization-request-handler.ts index 7def1a9..41af90c 100644 --- a/src/authorization-request-handler.ts +++ b/src/authorization-request-handler.ts @@ -28,18 +28,18 @@ export class IonicAuthorizationRequestHandler extends AuthorizationRequestHandle constructor( private browser: Browser, private storage: StorageBackend, + crypto = new DefaultCrypto(), utils = new BasicQueryStringUtils(), - private generateRandom = new DefaultCrypto() ) { - super(utils, generateRandom); + super(utils, crypto); } public async performAuthorizationRequest(configuration: AuthorizationServiceConfiguration, request: AuthorizationRequest): Promise { - let handle = this.generateRandom.generateRandom(10); + const handle = this.crypto.generateRandom(10); await this.storage.setItem(AUTHORIZATION_REQUEST_HANDLE_KEY, handle); await this.storage.setItem(authorizationRequestKey(handle), JSON.stringify(await request.toJson())); - let url = this.buildRequestUrl(configuration, request); - let returnedUrl: string | undefined = await this.browser.showWindow(url, request.redirectUri); + const url = this.buildRequestUrl(configuration, request); + const returnedUrl: string | undefined = await this.browser.showWindow(url, request.redirectUri); //callback may come from showWindow or via another method if (returnedUrl != undefined) { await this.storage.setItem(AUTHORIZATION_RESPONSE_KEY, returnedUrl); @@ -48,17 +48,17 @@ export class IonicAuthorizationRequestHandler extends AuthorizationRequestHandle } protected async completeAuthorizationRequest(): Promise { - let handle = await this.storage.getItem(AUTHORIZATION_REQUEST_HANDLE_KEY); + const handle = await this.storage.getItem(AUTHORIZATION_REQUEST_HANDLE_KEY); if (!handle) { throw new Error('Handle Not Available'); } - let request: AuthorizationRequest = this.getAuthorizationRequest(await this.storage.getItem(authorizationRequestKey(handle))); - let queryParams = this.getQueryParams(await this.storage.getItem(AUTHORIZATION_RESPONSE_KEY)); + const request: AuthorizationRequest = this.getAuthorizationRequest(await this.storage.getItem(authorizationRequestKey(handle))); + const queryParams = this.getQueryParams(await this.storage.getItem(AUTHORIZATION_RESPONSE_KEY)); this.removeItemsFromStorage(handle); - let state: string | undefined = queryParams['state']; - let error: string | undefined = queryParams['error']; + const state: string | undefined = queryParams['state']; + const error: string | undefined = queryParams['error']; if (state !== request.state) { throw new Error('State Does Not Match'); @@ -75,11 +75,11 @@ export class IonicAuthorizationRequestHandler extends AuthorizationRequestHandle if (authRequest == null) { throw new Error('No Auth Request Available'); } - return new AuthorizationRequest(JSON.parse(authRequest)); + return new AuthorizationRequest(JSON.parse(authRequest), this.crypto); } private getAuthorizationError(queryParams: StringMap): AuthorizationError { - let authorizationErrorJSON: AuthorizationErrorJson = { + const authorizationErrorJSON: AuthorizationErrorJson = { error: queryParams['error'], error_description: queryParams['error_description'], error_uri: undefined, @@ -89,7 +89,7 @@ export class IonicAuthorizationRequestHandler extends AuthorizationRequestHandle } private getAuthorizationResponse(queryParams: StringMap): AuthorizationResponse { - let authorizationResponseJSON: AuthorizationResponseJson = { + const authorizationResponseJSON: AuthorizationResponseJson = { code: queryParams['code'], state: queryParams['state'], }; @@ -104,10 +104,10 @@ export class IonicAuthorizationRequestHandler extends AuthorizationRequestHandle private getQueryParams(authResponse: string | null): StringMap { if (authResponse != null) { - let querySide: string = authResponse.split('#')[0]; - let parts: string[] = querySide.split('?'); + const querySide: string = authResponse.split('#')[0]; + const parts: string[] = querySide.split('?'); if (parts.length !== 2) throw new Error('Invalid auth response string'); - let hash = parts[1]; + const hash = parts[1]; return this.utils.parseQueryString(hash); } else { return {}; diff --git a/src/cordova/cordova-secure-storage.ts b/src/cordova/cordova-secure-storage.ts index 3288821..a6b78af 100644 --- a/src/cordova/cordova-secure-storage.ts +++ b/src/cordova/cordova-secure-storage.ts @@ -1,23 +1,24 @@ -import { CordovaDocument } from './cordova-document'; -import { StorageBackend } from '@openid/appauth'; import { SecureStorage, SecureStorageObject } from '@awesome-cordova-plugins/secure-storage'; +import { StorageBackend } from '@openid/appauth'; + +import { CordovaDocument } from './cordova-document'; // REQUIRES CORDOVA PLUGINS // cordova-plugin-secure-storage export class CordovaSecureStorage extends StorageBackend { private localData: any = {}; - private KEYSTORE: string = 'SecretStore'; + private KEYSTORE = 'SecretStore'; public async SecureStorageExists(): Promise { await CordovaDocument.ready(); return SecureStorage.create(this.KEYSTORE).then( () => true, - () => false + () => false, ); } public async hasRecord(store: SecureStorageObject, key: string) { - let keys: string[] = await store.keys(); + const keys: string[] = await store.keys(); return keys.indexOf(key) > -1; } diff --git a/src/end-session-request-handler.ts b/src/end-session-request-handler.ts index 4f8e13e..d8ec100 100644 --- a/src/end-session-request-handler.ts +++ b/src/end-session-request-handler.ts @@ -1,32 +1,36 @@ -import { EndSessionRequest } from './end-session-request'; -import { AuthorizationServiceConfiguration, StringMap, BasicQueryStringUtils } from '@openid/appauth'; +import { AuthorizationServiceConfiguration, BasicQueryStringUtils, StringMap } from '@openid/appauth'; + import { Browser } from './auth-browser'; +import { EndSessionRequest } from './end-session-request'; export interface EndSessionHandler { performEndSessionRequest(configuration: AuthorizationServiceConfiguration, request: EndSessionRequest): Promise; } export class IonicEndSessionHandler implements EndSessionHandler { - constructor(private browser: Browser, private utils = new BasicQueryStringUtils()) {} + constructor( + private browser: Browser, + private utils = new BasicQueryStringUtils(), + ) {} public async performEndSessionRequest( configuration: AuthorizationServiceConfiguration, - request: EndSessionRequest + request: EndSessionRequest, ): Promise { - let url = this.buildRequestUrl(configuration, request); + const url = this.buildRequestUrl(configuration, request); return this.browser.showWindow(url, request.postLogoutRedirectURI); } private buildRequestUrl(configuration: AuthorizationServiceConfiguration, request: EndSessionRequest) { - let requestMap: StringMap = { + const requestMap: StringMap = { id_token_hint: request.idTokenHint, post_logout_redirect_uri: request.postLogoutRedirectURI, state: request.state, }; - let query = this.utils.stringify(requestMap); - let baseUrl = configuration.endSessionEndpoint; - let url = `${baseUrl}?${query}`; + const query = this.utils.stringify(requestMap); + const baseUrl = configuration.endSessionEndpoint; + const url = `${baseUrl}?${query}`; return url; } } diff --git a/test/unit/auth-service.spec.ts b/test/unit/auth-service.spec.ts index 83ec4ae..718a881 100644 --- a/test/unit/auth-service.spec.ts +++ b/test/unit/auth-service.spec.ts @@ -1,12 +1,14 @@ import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; -import { mock, instance, when, anything } from 'ts-mockito'; +import { anyNumber, anyString, anything, instance, mock, spy, verify, when } from 'ts-mockito'; + import { AuthorizationServiceConfigurationJson, JQueryRequestor, LocalStorageBackend, TokenResponse } from '@openid/appauth'; + +import { AuthActions, IAuthAction } from '../../src/auth-action'; import { Browser, DefaultBrowser } from '../../src/auth-browser'; -import { AuthService } from '../../src/auth-service'; -import { IAuthConfig, AuthenticationType } from '../../src/auth-configuration'; +import { AuthenticationType, IAuthConfig } from '../../src/auth-configuration'; import { AuthObserver } from '../../src/auth-observer'; -import { AuthActions, IAuthAction } from '../../src/auth-action'; +import { AuthService } from '../../src/auth-service'; chai.use(chaiAsPromised); const TOKEN_RESPONSE_KEY = 'token_response'; @@ -31,7 +33,7 @@ async function buildAuthServiceAndInit(withToken: boolean): Promise userinfo_endpoint: 'userinfo_endpointTest', }; when(mockedRequestorClass.xhr(anything())).thenReturn( - new Promise((resolve) => resolve(authServiceConfigJson)) + new Promise((resolve) => resolve(authServiceConfigJson)), ); const mockedRequestor = instance(mockedRequestorClass); @@ -120,4 +122,64 @@ describe('auth service Tests', () => { const authService: AuthService = await buildAuthServiceAndInit(false); await authService.refreshToken(); }); + + it(`should accept a custom crypto instance when using PKCE`, async () => { + class CustomCrypto { + generateRandom(size: number): string { + // console.log('random_' + size); + return 'random_' + size; + } + + deriveChallenge(code: string) { + // console.log('challenge_' + code); + return Promise.resolve('challenge_' + code); + } + } + + const mockedRequestorClass: JQueryRequestor = mock(JQueryRequestor); + const authServiceConfigJson: AuthorizationServiceConfigurationJson = { + authorization_endpoint: '', + token_endpoint: 'token_endpointTest', + revocation_endpoint: 'revocation_endpointTest', + end_session_endpoint: 'end_session_endpointTest', + userinfo_endpoint: 'userinfo_endpointTest', + }; + when(mockedRequestorClass.xhr(anything())).thenReturn( + new Promise((resolve) => resolve(authServiceConfigJson)), + ); + const mockedRequestor = instance(mockedRequestorClass); + + const mockedBrowserClass: Browser = mock(DefaultBrowser); + const promiseUrlString: Promise = new Promise((resolve) => { + resolve('returnedUrlTest?state=' + state + '#'); + }); + when(mockedBrowserClass.showWindow(anything(), anything())).thenReturn(promiseUrlString); + when(mockedBrowserClass.closeWindow()).thenReturn(new Promise(() => {})); + + const mockedBrowser = instance(mockedBrowserClass); + + const storage: Storage = new Storage(); + + const customCrypto = new CustomCrypto(); + const customCryptoSpy = spy(customCrypto); + + const authService: AuthService = new AuthService(mockedBrowser, new LocalStorageBackend(storage), mockedRequestor, customCrypto); + + const authConfig: IAuthConfig = { + client_id: 'clientIdTest', + client_secret: 'clientSecretTest', + server_host: 'serverHostTest', + redirect_url: 'redirectUrlTest', + end_session_redirect_url: 'endSessionRedirectTest', + scopes: `${AuthenticationType.Token}scopesTest`, + pkce: true, + }; + + authService.authConfig = authConfig; + await authService.init(); + await authService.signIn(); + + verify(customCryptoSpy.generateRandom(anyNumber())).atLeast(4); + verify(customCryptoSpy.deriveChallenge(anyString())).atLeast(2); + }); }); diff --git a/test/unit/authorization-request-handler.spec.ts b/test/unit/authorization-request-handler.spec.ts index eb45396..c6438f3 100644 --- a/test/unit/authorization-request-handler.spec.ts +++ b/test/unit/authorization-request-handler.spec.ts @@ -5,7 +5,7 @@ import { Browser, DefaultBrowser } from '../../src/auth-browser'; import { DefaultCrypto, AuthorizationServiceConfiguration, AuthorizationRequest, AuthorizationRequestJson } from '@openid/appauth'; import { IonicStorage } from '../../src/auth-storage'; -let authRequestJson: AuthorizationRequestJson = { +const authRequestJson: AuthorizationRequestJson = { response_type: 'response_typeTest', client_id: 'client_idTest', redirect_uri: 'redirect_uriTest', @@ -26,20 +26,15 @@ async function performIonicRequestHandlerAuthReq(url: string | undefined, mocked const mockedAuthorizationServiceConfiguration = instance(mockedAuthorizationServiceConfigurationClass); const storage: IonicStorage = new IonicStorage(); - let crypto: DefaultCrypto = new DefaultCrypto(); + let crypto = new DefaultCrypto(); if (mockedCrypto) { crypto = mockedCrypto; } - const ionicAuthorizationRequestHandler: IonicAuthorizationRequestHandler = new IonicAuthorizationRequestHandler( - mockedBrowser, - storage, - undefined, - crypto - ); + const ionicAuthorizationRequestHandler = new IonicAuthorizationRequestHandler(mockedBrowser, storage, crypto, undefined); await ionicAuthorizationRequestHandler.performAuthorizationRequest( mockedAuthorizationServiceConfiguration, - new AuthorizationRequest(authRequestJson, crypto, false) + new AuthorizationRequest(authRequestJson, crypto, false), ); return storage.getItem(AUTHORIZATION_RESPONSE_KEY); diff --git a/test/unit/capacitor/capacitor-secure-storage.spec.ts b/test/unit/capacitor/capacitor-secure-storage.spec.ts index 14a4e5c..d760140 100644 --- a/test/unit/capacitor/capacitor-secure-storage.spec.ts +++ b/test/unit/capacitor/capacitor-secure-storage.spec.ts @@ -1,10 +1,11 @@ +import * as secureStorageModule from 'capacitor-secure-storage-plugin'; import { expect } from 'chai'; -import { CapacitorSecureStorage } from '../../../src/capacitor/capacitor-secure-storage'; import { ImportMock } from 'ts-mock-imports'; -import * as secureStorageModule from 'capacitor-secure-storage-plugin'; -const KEY: string = 'KEY'; -const value: string = 'value'; +import { CapacitorSecureStorage } from '../../../src/capacitor/capacitor-secure-storage'; + +const KEY = 'KEY'; +const value = 'value'; const mockManager = ImportMock.mockStaticClass(secureStorageModule, 'SecureStoragePlugin'); describe('capacitor secure storage Tests', () => { @@ -22,7 +23,7 @@ describe('capacitor secure storage Tests', () => { new Promise((resolve, reject) => { resolve(value); reject(null); - }) + }), ); storage.getItem(KEY).then((returnedValue) => { expect(returnedValue).to.be.equal(value); diff --git a/test/unit/end-session-request-handler.spec.ts b/test/unit/end-session-request-handler.spec.ts index 0822f0f..5c2497d 100644 --- a/test/unit/end-session-request-handler.spec.ts +++ b/test/unit/end-session-request-handler.spec.ts @@ -25,7 +25,7 @@ describe('end Session request handler Tests', () => { const ionicEndSessionHandler: IonicEndSessionHandler = new IonicEndSessionHandler(mockedBrowser); const urlResult = await ionicEndSessionHandler.performEndSessionRequest( mockedAuthorizationServiceConfiguration, - mockedEndSessionRequest + mockedEndSessionRequest, ); expect(urlResult).to.equal(returnedUrl); });