{"version":3,"sources":["node_modules/@ngxs/form-plugin/fesm2022/ngxs-form-plugin.mjs","node_modules/@ory/integrations/ui/index.mjs","src/app/core/components/kratos/form.component.ts","src/app/core/components/kratos/form.component.html","src/app/store/communication/broadcast-channels.actions.ts","src/app/store/communication/broadcast-channels.service.ts","src/app/store/communication/broadcast-channels.state.ts","src/app/store/communication/broadcast-channels.state.module.ts","src/app/pages/internal/settings/pages/settings.component.ts","src/app/pages/internal/settings/pages/settings.component.html","src/app/core/dialogs/reauthenticate/reauthenticate.component.ts","src/app/core/dialogs/reauthenticate/reauthenticate.component.html"],"sourcesContent":["import * as i0 from '@angular/core';\nimport { Injectable, inject, ChangeDetectorRef, Directive, Input, NgModule } from '@angular/core';\nimport { Actions, Store, ofActionDispatched, withNgxsPlugin } from '@ngxs/store';\nimport { getActionTypeFromInstance, setValue, getValue } from '@ngxs/store/plugins';\nimport { FormGroupDirective } from '@angular/forms';\nimport { ReplaySubject } from 'rxjs';\nimport { filter, takeUntil, distinctUntilChanged, debounceTime } from 'rxjs/operators';\nlet UpdateFormStatus = /*#__PURE__*/(() => {\n class UpdateFormStatus {\n static {\n this.type = '[Forms] Update Form Status';\n }\n constructor(payload) {\n this.payload = payload;\n }\n }\n return UpdateFormStatus;\n})();\nlet UpdateFormValue = /*#__PURE__*/(() => {\n class UpdateFormValue {\n static {\n this.type = '[Forms] Update Form Value';\n }\n constructor(payload) {\n this.payload = payload;\n }\n }\n return UpdateFormValue;\n})();\nlet UpdateForm = /*#__PURE__*/(() => {\n class UpdateForm {\n static {\n this.type = '[Forms] Update Form';\n }\n constructor(payload) {\n this.payload = payload;\n }\n }\n return UpdateForm;\n})();\nlet UpdateFormDirty = /*#__PURE__*/(() => {\n class UpdateFormDirty {\n static {\n this.type = '[Forms] Update Form Dirty';\n }\n constructor(payload) {\n this.payload = payload;\n }\n }\n return UpdateFormDirty;\n})();\nlet SetFormDirty = /*#__PURE__*/(() => {\n class SetFormDirty {\n static {\n this.type = '[Forms] Set Form Dirty';\n }\n constructor(payload) {\n this.payload = payload;\n }\n }\n return SetFormDirty;\n})();\nlet SetFormPristine = /*#__PURE__*/(() => {\n class SetFormPristine {\n static {\n this.type = '[Forms] Set Form Pristine';\n }\n constructor(payload) {\n this.payload = payload;\n }\n }\n return SetFormPristine;\n})();\nlet UpdateFormErrors = /*#__PURE__*/(() => {\n class UpdateFormErrors {\n static {\n this.type = '[Forms] Update Form Errors';\n }\n constructor(payload) {\n this.payload = payload;\n }\n }\n return UpdateFormErrors;\n})();\nlet SetFormDisabled = /*#__PURE__*/(() => {\n class SetFormDisabled {\n static {\n this.type = '[Forms] Set Form Disabled';\n }\n constructor(payload) {\n this.payload = payload;\n }\n }\n return SetFormDisabled;\n})();\nlet SetFormEnabled = /*#__PURE__*/(() => {\n class SetFormEnabled {\n static {\n this.type = '[Forms] Set Form Enabled';\n }\n constructor(payload) {\n this.payload = payload;\n }\n }\n return SetFormEnabled;\n})();\nlet ResetForm = /*#__PURE__*/(() => {\n class ResetForm {\n static {\n this.type = '[Forms] Reset Form';\n }\n constructor(payload) {\n this.payload = payload;\n }\n }\n return ResetForm;\n})();\nlet NgxsFormPlugin = /*#__PURE__*/(() => {\n class NgxsFormPlugin {\n handle(state, event, next) {\n const type = getActionTypeFromInstance(event);\n let nextState = state;\n if (type === UpdateFormValue.type || type === UpdateForm.type || type === ResetForm.type) {\n const {\n value\n } = event.payload;\n const payloadValue = Array.isArray(value) ? value.slice() : isObjectLike(value) ? {\n ...value\n } : value;\n const path = this.joinPathWithPropertyPath(event);\n nextState = setValue(nextState, path, payloadValue);\n }\n if (type === ResetForm.type) {\n const model = getValue(nextState, `${event.payload.path}.model`);\n nextState = setValue(nextState, `${event.payload.path}`, {\n model: model\n });\n }\n if (type === UpdateFormStatus.type || type === UpdateForm.type) {\n nextState = setValue(nextState, `${event.payload.path}.status`, event.payload.status);\n }\n if (type === UpdateFormErrors.type || type === UpdateForm.type) {\n nextState = setValue(nextState, `${event.payload.path}.errors`, {\n ...event.payload.errors\n });\n }\n if (type === UpdateFormDirty.type || type === UpdateForm.type) {\n nextState = setValue(nextState, `${event.payload.path}.dirty`, event.payload.dirty);\n }\n if (type === SetFormDirty.type) {\n nextState = setValue(nextState, `${event.payload}.dirty`, true);\n }\n if (type === SetFormPristine.type) {\n nextState = setValue(nextState, `${event.payload}.dirty`, false);\n }\n if (type === SetFormDisabled.type) {\n nextState = setValue(nextState, `${event.payload}.disabled`, true);\n }\n if (type === SetFormEnabled.type) {\n nextState = setValue(nextState, `${event.payload}.disabled`, false);\n }\n return next(nextState, event);\n }\n joinPathWithPropertyPath({\n payload\n }) {\n let path = `${payload.path}.model`;\n if (payload.propertyPath) {\n path += `.${payload.propertyPath}`;\n }\n return path;\n }\n /** @nocollapse */\n static {\n this.ɵfac = function NgxsFormPlugin_Factory(__ngFactoryType__) {\n return new (__ngFactoryType__ || NgxsFormPlugin)();\n };\n }\n /** @nocollapse */\n static {\n this.ɵprov = /* @__PURE__ */i0.ɵɵdefineInjectable({\n token: NgxsFormPlugin,\n factory: NgxsFormPlugin.ɵfac\n });\n }\n }\n return NgxsFormPlugin;\n})();\n(() => {\n (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\nfunction isObjectLike(target) {\n return target !== null && typeof target === 'object';\n}\nlet NgxsFormDirective = /*#__PURE__*/(() => {\n class NgxsFormDirective {\n constructor() {\n this.path = null;\n this._debounce = 100;\n this._clearDestroy = false;\n this._updating = false;\n this._actions$ = inject(Actions);\n this._store = inject(Store);\n this._formGroupDirective = inject(FormGroupDirective);\n this._cd = inject(ChangeDetectorRef);\n this._destroy$ = new ReplaySubject(1);\n }\n set debounce(debounce) {\n this._debounce = Number(debounce);\n }\n get debounce() {\n return this._debounce;\n }\n set clearDestroy(val) {\n this._clearDestroy = val != null && `${val}` !== 'false';\n }\n get clearDestroy() {\n return this._clearDestroy;\n }\n ngOnInit() {\n this._actions$.pipe(ofActionDispatched(ResetForm), filter(action => action.payload.path === this.path), takeUntil(this._destroy$)).subscribe(({\n payload: {\n value\n }\n }) => {\n this.form.reset(value);\n this.updateFormStateWithRawValue(true);\n this._cd.markForCheck();\n });\n this.getStateStream(`${this.path}.model`).subscribe(model => {\n if (this._updating || !model) {\n return;\n }\n this.form.patchValue(model);\n this._cd.markForCheck();\n });\n this.getStateStream(`${this.path}.dirty`).subscribe(dirty => {\n if (this.form.dirty === dirty || typeof dirty !== 'boolean') {\n return;\n }\n if (dirty) {\n this.form.markAsDirty();\n } else {\n this.form.markAsPristine();\n }\n this._cd.markForCheck();\n });\n // On first state change, sync form model, status and dirty with state\n this._store.selectOnce(state => getValue(state, this.path)).subscribe(() => {\n this._store.dispatch([new UpdateFormValue({\n path: this.path,\n value: this.form.getRawValue()\n }), new UpdateFormStatus({\n path: this.path,\n status: this.form.status\n }), new UpdateFormDirty({\n path: this.path,\n dirty: this.form.dirty\n })]);\n });\n this.getStateStream(`${this.path}.disabled`).subscribe(disabled => {\n if (this.form.disabled === disabled || typeof disabled !== 'boolean') {\n return;\n }\n if (disabled) {\n this.form.disable();\n } else {\n this.form.enable();\n }\n this._cd.markForCheck();\n });\n this._formGroupDirective.valueChanges.pipe(distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)), this.debounceChange()).subscribe(() => {\n this.updateFormStateWithRawValue();\n });\n this._formGroupDirective.statusChanges.pipe(distinctUntilChanged(), this.debounceChange()).subscribe(status => {\n this._store.dispatch(new UpdateFormStatus({\n status,\n path: this.path\n }));\n });\n }\n updateFormStateWithRawValue(withFormStatus) {\n if (this._updating) return;\n const value = this._formGroupDirective.control.getRawValue();\n const actions = [new UpdateFormValue({\n path: this.path,\n value\n }), new UpdateFormDirty({\n path: this.path,\n dirty: this._formGroupDirective.dirty\n }), new UpdateFormErrors({\n path: this.path,\n errors: this._formGroupDirective.errors\n })];\n if (withFormStatus) {\n actions.push(new UpdateFormStatus({\n path: this.path,\n status: this._formGroupDirective.status\n }));\n }\n this._updating = true;\n this._store.dispatch(actions).subscribe({\n error: () => this._updating = false,\n complete: () => this._updating = false\n });\n }\n ngOnDestroy() {\n this._destroy$.next();\n if (this.clearDestroy) {\n this._store.dispatch(new UpdateForm({\n path: this.path,\n value: null,\n dirty: null,\n status: null,\n errors: null\n }));\n }\n }\n debounceChange() {\n const skipDebounceTime = this._formGroupDirective.control.updateOn !== 'change' || this._debounce < 0;\n return skipDebounceTime ? change => change.pipe(takeUntil(this._destroy$)) : change => change.pipe(debounceTime(this._debounce), takeUntil(this._destroy$));\n }\n get form() {\n return this._formGroupDirective.form;\n }\n getStateStream(path) {\n return this._store.select(state => getValue(state, path)).pipe(takeUntil(this._destroy$));\n }\n /** @nocollapse */\n static {\n this.ɵfac = function NgxsFormDirective_Factory(__ngFactoryType__) {\n return new (__ngFactoryType__ || NgxsFormDirective)();\n };\n }\n /** @nocollapse */\n static {\n this.ɵdir = /* @__PURE__ */i0.ɵɵdefineDirective({\n type: NgxsFormDirective,\n selectors: [[\"\", \"ngxsForm\", \"\"]],\n inputs: {\n path: [0, \"ngxsForm\", \"path\"],\n debounce: [0, \"ngxsFormDebounce\", \"debounce\"],\n clearDestroy: [0, \"ngxsFormClearOnDestroy\", \"clearDestroy\"]\n }\n });\n }\n }\n return NgxsFormDirective;\n})();\n(() => {\n (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\nlet NgxsFormPluginModule = /*#__PURE__*/(() => {\n class NgxsFormPluginModule {\n static forRoot() {\n return {\n ngModule: NgxsFormPluginModule,\n providers: [withNgxsPlugin(NgxsFormPlugin)]\n };\n }\n /** @nocollapse */\n static {\n this.ɵfac = function NgxsFormPluginModule_Factory(__ngFactoryType__) {\n return new (__ngFactoryType__ || NgxsFormPluginModule)();\n };\n }\n /** @nocollapse */\n static {\n this.ɵmod = /* @__PURE__ */i0.ɵɵdefineNgModule({\n type: NgxsFormPluginModule\n });\n }\n /** @nocollapse */\n static {\n this.ɵinj = /* @__PURE__ */i0.ɵɵdefineInjector({});\n }\n }\n return NgxsFormPluginModule;\n})();\n(() => {\n (typeof ngDevMode === \"undefined\" || ngDevMode) && void 0;\n})();\nfunction withNgxsFormPlugin() {\n return withNgxsPlugin(NgxsFormPlugin);\n}\n\n/**\n * The public api for consumers of @ngxs/form-plugin\n */\n\n/**\n * Generated bundle index. Do not edit.\n */\n\nexport { NgxsFormDirective, NgxsFormPlugin, NgxsFormPluginModule, ResetForm, SetFormDirty, SetFormDisabled, SetFormEnabled, SetFormPristine, UpdateForm, UpdateFormDirty, UpdateFormErrors, UpdateFormStatus, UpdateFormValue, withNgxsFormPlugin };\n","const getNodeLabel = node => {\n const attributes = node.attributes;\n if (isUiNodeAnchorAttributes(attributes)) {\n return attributes.title.text;\n }\n if (isUiNodeImageAttributes(attributes)) {\n return node.meta.label?.text || \"\";\n }\n if (isUiNodeInputAttributes(attributes)) {\n if (attributes.label?.text) {\n return attributes.label.text;\n }\n }\n return node.meta.label?.text || \"\";\n};\nfunction isUiNodeAnchorAttributes(attrs) {\n return attrs.node_type === \"a\";\n}\nfunction isUiNodeImageAttributes(attrs) {\n return attrs.node_type === \"img\";\n}\nfunction isUiNodeInputAttributes(attrs) {\n return attrs.node_type === \"input\";\n}\nfunction isUiNodeTextAttributes(attrs) {\n return attrs.node_type === \"text\";\n}\nfunction isUiNodeScriptAttributes(attrs) {\n return attrs.node_type === \"script\";\n}\nfunction getNodeId({\n attributes\n}) {\n if (isUiNodeInputAttributes(attributes)) {\n return attributes.name;\n } else {\n return attributes.id;\n }\n}\nconst getNodeInputType = attr => attr?.[\"type\"] ?? \"\";\nconst filterNodesByGroups = ({\n nodes,\n groups,\n withoutDefaultGroup,\n attributes,\n withoutDefaultAttributes,\n excludeAttributes\n}) => {\n const search = s => typeof s === \"string\" ? s.split(\",\") : s;\n return nodes.filter(({\n group,\n attributes: attr\n }) => {\n if (!groups && !attributes && !excludeAttributes) return true;\n const g = search(groups) || [];\n if (!withoutDefaultGroup) {\n g.push(\"default\");\n }\n const a = search(attributes) || [];\n if (!withoutDefaultAttributes) {\n if (group.includes(\"default\")) {\n a.push(\"hidden\");\n }\n if (group.includes(\"webauthn\") || group.includes(\"totp\")) {\n a.push(\"input\", \"script\");\n }\n }\n const ea = search(excludeAttributes) || [];\n const filterGroup = groups ? g.includes(group) : true;\n const filterAttributes = attributes ? a.includes(getNodeInputType(attr)) : true;\n const filterExcludeAttributes = excludeAttributes ? !ea.includes(getNodeInputType(attr)) : true;\n return filterGroup && filterAttributes && filterExcludeAttributes;\n });\n};\nexport { filterNodesByGroups, getNodeId, getNodeInputType, getNodeLabel, isUiNodeAnchorAttributes, isUiNodeImageAttributes, isUiNodeInputAttributes, isUiNodeScriptAttributes, isUiNodeTextAttributes };\n","import {\n ChangeDetectorRef,\n Component,\n EventEmitter,\n Input,\n OnChanges,\n Output,\n SimpleChanges,\n inject,\n} from '@angular/core';\nimport {\n FormBuilder,\n FormGroup,\n ReactiveFormsModule,\n Validators,\n} from '@angular/forms';\nimport {\n LoginFlow,\n RecoveryFlow,\n RegistrationFlow,\n SettingsFlow,\n UiNode,\n UiNodeInputAttributes,\n UiText,\n} from '@ory/client';\nimport { KratosAuthenticationService } from 'src/app/services/authentication/kratos.service';\n\nimport { TranslateService } from '@ngx-translate/core';\nimport {\n FilterNodesByGroups,\n filterNodesByGroups,\n getNodeLabel,\n isUiNodeImageAttributes,\n isUiNodeInputAttributes,\n isUiNodeTextAttributes,\n} from '@ory/integrations/ui';\nimport { SharedModule } from '../../shared.module';\nimport { VButtonComponent } from '../ui-kit/buttons/button/button.component';\nimport { VInputFieldComponent } from '../ui-kit/input-field/input-field.component';\nimport { VInputComponent } from '../ui-kit/input/input.component';\nimport { VSSOButtonComponent } from '../ui-kit/sso-button/sso-button.component';\n\n@Component({\n selector: 'app-kratos-form',\n templateUrl: './form.component.html',\n styleUrls: ['./form.component.scss'],\n imports: [\n SharedModule,\n VButtonComponent,\n ReactiveFormsModule,\n VInputFieldComponent,\n VInputComponent,\n VSSOButtonComponent,\n ],\n providers: [KratosAuthenticationService],\n})\nexport class KratosFormComponent implements OnChanges {\n private fb = inject(FormBuilder);\n private cd = inject(ChangeDetectorRef);\n private translate = inject(TranslateService);\n\n @Input() loading = false;\n @Input() flow?: RegistrationFlow | LoginFlow | RecoveryFlow | SettingsFlow;\n @Input() groups: string[] = [];\n\n // testIdPrefix is used to prefix the test ids of the form elements\n @Input() testIdPrefix?: string;\n\n @Output() kratosFormSubmit = new EventEmitter();\n\n kratosForm: FormGroup = this.fb.group({});\n uiNodes: UiNode[] = [];\n\n formMessages: UiText[] = [];\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['flow']) {\n this.setFlow(changes['flow'].currentValue);\n }\n if (changes['loading']) {\n if (changes['loading'].currentValue) {\n this.kratosForm.disable();\n } else {\n this.kratosForm.enable();\n }\n }\n }\n\n public getVisibleNodes(nodes: UiNode[]): UiNode[] {\n const visibleNodes = this.filterUINodes({\n nodes: nodes,\n withoutDefaultGroup: true,\n groups: this.groups,\n excludeAttributes: ['submit', 'button'],\n }).filter(node => {\n if (node.attributes.node_type === 'input') {\n return (node.attributes as UiNodeInputAttributes).type !== 'hidden';\n }\n if (node.attributes.node_type === 'script') {\n return false;\n }\n return true;\n });\n\n return visibleNodes;\n }\n\n public isInputNode(node: UiNode) {\n return isUiNodeInputAttributes(node.attributes);\n }\n\n public isImageNode(node: UiNode) {\n return isUiNodeImageAttributes(node.attributes);\n }\n\n public isTextNode(node: UiNode) {\n return isUiNodeTextAttributes(node.attributes);\n }\n public getTestId(node: UiNode) {\n const label = getNodeLabel(node).toLowerCase().replaceAll(' ', '-');\n return `${this.testIdPrefix}${(node.attributes as any).type}-${label}`;\n }\n\n public getUiNodeLabel(node: UiNode) {\n const label = getNodeLabel(node).toLowerCase();\n\n switch (label) {\n case 'e-mail':\n case 'email':\n case 'id':\n return 'components.kratosForm.emailInput';\n case 'password':\n return 'components.kratosForm.passwordInput';\n case 'first name':\n return 'components.kratosForm.firstnameInput';\n case 'last name':\n return 'components.kratosForm.lastnameInput';\n case 'authenticator app qr code':\n return 'components.kratosForm.twoFAQRCode';\n case 'unlink totp authenticator app':\n return 'components.kratosForm.unlinkTotp';\n case 'authentication code':\n return 'components.kratosForm.authenticationCode';\n case 'this is your authenticator app secret. use it if you can not scan the qr code.':\n return 'components.kratosForm.twoFAManualCode';\n case 'verify code':\n return 'components.kratosForm.twoFAVerifyCode';\n case 'sign in':\n return 'components.kratosForm.signInBtn';\n case 'sign in and link':\n return 'components.kratosForm.signInAndLinkBtn';\n case 'sign up':\n return 'components.kratosForm.signUpBtn';\n case 'submit':\n return 'components.kratosForm.submitBtn';\n case 'save':\n return 'components.kratosForm.saveBtn';\n case 'resend code':\n return 'components.kratosForm.resendCode';\n case 'use authenticator':\n return 'components.kratosForm.twoFaUseTOTP';\n case 'use security key':\n return 'components.kratosForm.twoFaUseSecurityKey';\n case 'add security key':\n return 'components.kratosForm.twoFaAddSecurityKey';\n case 'name of the security key':\n return 'components.kratosForm.twoFaAddSecurityKeyName';\n }\n\n const removeKeyRegex = /remove security key \"(.*)\"/.exec(label);\n if (removeKeyRegex) {\n return this.translate.instant(\n 'components.kratosForm.twoFaRemoveSecurityKey',\n { keyName: removeKeyRegex[1] }\n );\n }\n\n return label;\n }\n\n public filterUINodes(filter: FilterNodesByGroups) {\n return filterNodesByGroups(filter);\n }\n\n public excludeGroups(groups: string[], excludeGroups: string[]) {\n return groups.filter(group => !excludeGroups.includes(group));\n }\n\n public showOIDCGroups(): boolean {\n return this.groups.includes('oidc');\n }\n\n public getOIDCProvider(node: UiNode) {\n return (node.attributes as any).value;\n }\n\n private setFormMessages(messages: UiText[]) {\n // remove 'Please confirm this action by verifying that it is you.' (1010004)\n // when 'Please complete the second authentication challenge.' (1010003) is also included\n\n if (messages.findIndex(m => m.id === 1010004) > -1) {\n messages = messages.filter(m => m.id !== 1010003);\n }\n\n this.formMessages = messages;\n }\n\n setFlow(flow: LoginFlow | RegistrationFlow | RecoveryFlow | SettingsFlow) {\n this.flow = flow;\n\n const nodes = this.filterUINodes({\n nodes: flow.ui.nodes,\n withoutDefaultAttributes: true,\n });\n\n this.setFormMessages(flow.ui.messages || []);\n\n // create form fields\n nodes.forEach(node => {\n // check if node is in group\n if (node.group !== 'default' && !this.groups.includes(node.group)) {\n return;\n }\n\n if (isUiNodeInputAttributes(node.attributes)) {\n // hidden elements like csrf_token are added as controls, but\n // will not be displayed in the form\n if (!this.kratosForm.controls[node.attributes.name]) {\n this.kratosForm?.addControl(\n node.attributes.name,\n this.fb.control(\n node.attributes.value,\n node.attributes.required ? Validators.required : null\n )\n );\n }\n }\n });\n\n this.uiNodes = flow.ui.nodes.map(node => {\n if (node.meta.label?.id === 1070008) {\n (node.attributes as any).type = 'button';\n }\n return node;\n });\n\n // wait for the change detection to run before setting\n // form control errors as they would be removed otherwise\n // due to re-rendering the form when setting the array\n this.cd.detectChanges();\n\n // create form fields\n nodes.forEach(node => {\n if (isUiNodeInputAttributes(node.attributes)) {\n const control = this.kratosForm.controls[node.attributes.name];\n\n // check for errors\n if (node.messages.length > 0) {\n control.setErrors({\n validation: true,\n });\n control.markAsTouched();\n }\n }\n });\n }\n\n submit(customBtnNode?: UiNode) {\n let kratosBody: any = {};\n\n this.uiNodes.forEach(node => {\n if (node.group !== 'default' && !this.groups.includes(node.group)) {\n return;\n }\n\n if (node.attributes.node_type === 'input') {\n const attributes = node.attributes as UiNodeInputAttributes;\n\n if (\n (customBtnNode && attributes.type === 'submit') ||\n attributes.type === 'button'\n ) {\n return;\n }\n\n this.createNestedObject(\n kratosBody,\n attributes.name,\n this.kratosForm?.value[attributes.name]\n );\n }\n });\n\n if (customBtnNode) {\n const attributes = customBtnNode.attributes as UiNodeInputAttributes;\n kratosBody.method = customBtnNode.group;\n kratosBody = this.createNestedObject(\n kratosBody,\n attributes.name,\n attributes.value\n );\n }\n\n this.kratosFormSubmit.emit(kratosBody);\n }\n\n createNestedObject(base: any, path: string, value: any) {\n const keys = path.split('.');\n keys.reduce((prev, curr, index) => {\n return (prev[curr] =\n index === keys.length - 1 ? value : prev[curr] || {});\n }, base);\n return base;\n }\n\n onBtnClick(node: UiNode) {\n const attributes = node.attributes as UiNodeInputAttributes;\n if (attributes.name === 'webauthn_register_trigger') {\n this.webauthnRegistration(node);\n } else if (attributes.name === 'webauthn_login_trigger') {\n this.webauthnLogin(node);\n } else {\n this.submit(node);\n }\n }\n\n public webauthnRegistration(node: UiNode) {\n const onClickAttr = (node.attributes as any).onclick;\n\n const startIndex = onClickAttr.indexOf('{');\n const endIndex = onClickAttr.lastIndexOf('}');\n const fidoConfig = JSON.parse(\n onClickAttr.substring(startIndex, endIndex + 1)\n );\n\n fidoConfig.publicKey.challenge = this.__oryWebAuthnBufferDecode(\n fidoConfig.publicKey.challenge\n );\n fidoConfig.publicKey.user.id = this.__oryWebAuthnBufferDecode(\n fidoConfig.publicKey.user.id\n );\n\n navigator.credentials.create(fidoConfig).then(res => {\n if (!res || res.type !== 'public-key')\n throw Error('failed to create public key');\n\n const credentials = res as PublicKeyCredential;\n const attestationObject =\n credentials.response as AuthenticatorAttestationResponse;\n\n const result = {\n id: credentials.id,\n rawId: this.__oryWebAuthnBufferEncode(credentials.rawId),\n type: credentials.type,\n response: {\n attestationObject: this.__oryWebAuthnBufferEncode(\n attestationObject.attestationObject\n ),\n clientDataJSON: this.__oryWebAuthnBufferEncode(\n credentials.response.clientDataJSON\n ),\n },\n };\n\n this.kratosForm.controls['webauthn_register'].setValue(\n JSON.stringify(result)\n );\n\n this.submit(node);\n });\n }\n\n public webauthnLogin(node: UiNode) {\n const onClickAttr = (node.attributes as any).onclick;\n\n const startIndex = onClickAttr.indexOf('{');\n const endIndex = onClickAttr.lastIndexOf('}');\n const fidoConfig = JSON.parse(\n onClickAttr.substring(startIndex, endIndex + 1)\n );\n\n fidoConfig.publicKey.challenge = this.__oryWebAuthnBufferDecode(\n fidoConfig.publicKey.challenge\n );\n\n fidoConfig.publicKey.allowCredentials =\n fidoConfig.publicKey.allowCredentials.map((value: any) => {\n return {\n ...value,\n id: this.__oryWebAuthnBufferDecode(value.id),\n };\n });\n\n navigator.credentials.get(fidoConfig).then(res => {\n if (!res || res.type !== 'public-key')\n throw Error('failed to create public key');\n\n const credentials = res as PublicKeyCredential;\n const attestationObject =\n credentials.response as AuthenticatorAssertionResponse;\n\n const result = {\n id: credentials.id,\n rawId: this.__oryWebAuthnBufferEncode(credentials.rawId),\n type: credentials.type,\n response: {\n authenticatorData: this.__oryWebAuthnBufferEncode(\n attestationObject.authenticatorData\n ),\n clientDataJSON: this.__oryWebAuthnBufferEncode(\n attestationObject.clientDataJSON\n ),\n signature: this.__oryWebAuthnBufferEncode(\n attestationObject.signature\n ),\n userHandle: this.__oryWebAuthnBufferEncode(\n attestationObject.userHandle!\n ),\n },\n };\n\n this.kratosForm.controls['webauthn_login'].setValue(\n JSON.stringify(result)\n );\n\n this.submit(node);\n });\n }\n\n __oryWebAuthnBufferDecode(value: any) {\n return Uint8Array.from(\n atob(value.replaceAll('-', '+').replaceAll('_', '/')),\n function (c) {\n return c.charCodeAt(0);\n }\n );\n }\n\n __oryWebAuthnBufferEncode(value: ArrayBuffer) {\n return btoa(String.fromCharCode.apply(null, new Uint8Array(value) as any))\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n }\n}\n","