diff --git a/assets/dist/srp.js b/assets/dist/srp.js index bb013261..8837be5b 100644 --- a/assets/dist/srp.js +++ b/assets/dist/srp.js @@ -23,6 +23,7 @@ System.register(["@main"], function (exports_1, context_1) { this.el = el; this.options = options; this.submitting = false; + this.disabledInputs = []; this.options = Object.assign({}, defaultOptions, this.options); this.init(); } @@ -45,20 +46,27 @@ System.register(["@main"], function (exports_1, context_1) { } }); this.el.addEventListener('invalid', () => { - this.submitting = false; + this.release(); }, true); } - disablePasswords() { - if (this.passwordInput.value) { - this.passwordInput.disabled = true; - setTimeout(() => { - this.passwordInput.disabled = false; - }, 1000); + release() { + this.submitting = false; + for (const disabledInput of this.disabledInputs) { + disabledInput.disabled = false; } - const inputs = this.el.querySelectorAll('[data-srp-override]'); - for (const input of inputs) { - if (input.value) { + } + getPasswordInputs() { + return [ + this.passwordInput, + ...this.el.querySelectorAll('[data-srp-override]') + ]; + } + disablePasswords() { + this.disabledInputs = []; + for (const input of this.getPasswordInputs()) { + if (input.value && !input.disabled) { input.disabled = true; + this.disabledInputs.push(input); setTimeout(() => { input.disabled = false; }, 1000); @@ -99,6 +107,7 @@ System.register(["@main"], function (exports_1, context_1) { this.options = options; this.fallback = false; this.submitting = false; + this.disabledInputs = []; this.options = Object.assign({}, defaultOptions, this.options); this.init(); } @@ -138,6 +147,10 @@ System.register(["@main"], function (exports_1, context_1) { } this.submitting = false; this.fallback = false; + this.getHiddenInput('srp[M2]').value = ''; + for (const disabledInput of this.disabledInputs) { + disabledInput.disabled = false; + } } async auth() { if (!this.identityInput.value || !this.passwordInput.value) { @@ -190,17 +203,18 @@ System.register(["@main"], function (exports_1, context_1) { } this.getHiddenInput('srp[M2]').value = M2.toString(16); } + getPasswordInputs() { + return [ + this.passwordInput, + ...this.el.querySelectorAll('[data-srp-override]') + ]; + } disablePasswords() { - if (this.passwordInput.value) { - this.passwordInput.disabled = true; - setTimeout(() => { - this.passwordInput.disabled = false; - }, 1000); - } - const inputs = this.el.querySelectorAll('[data-srp-override]'); - for (const input of inputs) { - if (input.value) { + this.disabledInputs = []; + for (const input of this.getPasswordInputs()) { + if (input.value && !input.disabled) { input.disabled = true; + this.disabledInputs.push(input); setTimeout(() => { input.disabled = false; }, 1000); diff --git a/assets/dist/srp.js.map b/assets/dist/srp.js.map index 92be102c..1b3320e9 100644 --- a/assets/dist/srp.js.map +++ b/assets/dist/srp.js.map @@ -1 +1 @@ -{"version":3,"sources":["srp.ts"],"names":[],"mappings":"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","file":"srp.js","sourcesContent":["import '@main';\nimport type { SRPOptions } from '../types/srp';\n\nconst defaultOptions: Partial = {\n identitySelector: '[data-input-identity]',\n passwordSelector: '[data-input-password]',\n size: 256,\n hasher: 'sha256'\n};\n\nconst $http = u.$http;\n\nclass SRPRegistration {\n identityInput: HTMLInputElement;\n passwordInput: HTMLInputElement;\n saltInput: HTMLInputElement;\n verifierInput: HTMLInputElement;\n\n public submitting = false;\n\n constructor(public el: HTMLFormElement, public options: Partial = {}) {\n this.options = Object.assign({}, defaultOptions, this.options);\n\n this.init();\n }\n\n init() {\n this.identityInput = this.el.querySelector(this.options.identitySelector);\n this.passwordInput = this.el.querySelector(this.options.passwordSelector);\n\n if (!this.identityInput || !this.passwordInput) {\n throw new Error('Identity or password input not found.');\n }\n\n this.el.addEventListener('submit', async (e) => {\n if (!this.submitting) {\n e.stopPropagation();\n e.preventDefault();\n e.stopImmediatePropagation();\n\n await this.register();\n\n this.disablePasswords();\n\n this.submitting = true;\n\n this.el.requestSubmit();\n\n return;\n }\n });\n\n this.el.addEventListener('invalid', () => {\n this.submitting = false;\n }, true);\n }\n\n disablePasswords() {\n if (this.passwordInput.value) {\n this.passwordInput.disabled = true;\n\n setTimeout(() => {\n this.passwordInput.disabled = false;\n }, 1000);\n }\n\n const inputs = this.el.querySelectorAll('[data-srp-override]');\n\n for (const input of inputs) {\n if (input.value) {\n input.disabled = true;\n\n setTimeout(() => {\n input.disabled = false;\n }, 1000);\n }\n }\n }\n\n createClient(): InstanceType {\n const client = SRPClient.create(\n this.options.prime,\n this.options.generator,\n this.options.key,\n );\n\n client.setSize(this.options.size);\n client.setHasher(this.options?.hasher);\n\n return client;\n }\n\n async register() {\n const client = this.createClient();\n\n const identity = this.identityInput.value;\n const password = this.passwordInput.value;\n\n let { salt, verifier } = await client.register(identity, password);\n\n const saltInput = this.getHiddenInput('srp[salt]');\n saltInput.value = salt.toString(16);\n\n const verifierInput = this.getHiddenInput('srp[verifier]');\n verifierInput.value = verifier.toString(16);\n }\n\n getHiddenInput(name: string) {\n return this.el.querySelector(`[name=\"${name}\"]`)\n || this.createHiddenInput(name);\n }\n\n createHiddenInput(name: string) {\n const input = document.createElement('input');\n\n input.type = 'hidden';\n input.name = name;\n\n this.el.appendChild(input);\n\n return input;\n }\n}\n\nclass SRPLogin {\n identityInput: HTMLInputElement;\n passwordInput: HTMLInputElement;\n saltInput: HTMLInputElement;\n verifierInput: HTMLInputElement;\n\n public fallback = false;\n public submitting = false;\n public submitter: HTMLButtonElement;\n\n constructor(public el: HTMLFormElement, public options: Partial = {}) {\n this.options = Object.assign({}, defaultOptions, this.options);\n\n this.init();\n }\n\n init() {\n this.identityInput = this.el.querySelector(this.options.identitySelector);\n this.passwordInput = this.el.querySelector(this.options.passwordSelector);\n\n if (!this.identityInput || !this.passwordInput) {\n throw new Error('Identity or password input not found.');\n }\n\n this.el.addEventListener('submit', async (e) => {\n this.submitter = e.submitter as HTMLButtonElement;\n\n if (!this.submitting) {\n e.stopPropagation();\n e.preventDefault();\n e.stopImmediatePropagation();\n\n try {\n await this.auth();\n } catch (e) {\n console.warn(e);\n }\n\n if (!this.fallback) {\n this.disablePasswords();\n }\n\n this.submitting = true;\n\n this.el.requestSubmit();\n\n return;\n }\n });\n\n this.el.addEventListener('invalid', () => {\n this.release();\n }, true);\n }\n\n release() {\n if (this.submitter) {\n this.submitter.disabled = false;\n }\n\n this.submitting = false;\n this.fallback = false;\n }\n\n async auth() {\n if (!this.identityInput.value || !this.passwordInput.value) {\n return;\n }\n\n if (this.submitter) {\n this.submitter.disabled = true;\n }\n\n const identity = this.identityInput.value;\n const password = this.passwordInput.value;\n\n const client = this.createClient();\n\n // Challenge\n const res = await $http.get(\n '@auth_ajax/srpChallenge{?identity}',\n {\n vars: {\n identity\n }\n }\n );\n\n const r = res.data.data;\n\n if (r == null) {\n return;\n }\n\n this.fallback = !!r.fallback;\n this.getHiddenInput('srp[fallback]').value = this.fallback ? '1' : '0';\n\n if (this.fallback) {\n return;\n }\n\n let { salt, B } = r;\n\n // Step1\n salt = hexToBigint(salt);\n B = hexToBigint(B);\n\n // Step 1\n const a = await client.generateRandomSecret();\n const A = await client.generatePublic(a);\n const x = await client.generatePasswordHash(salt, identity, password);\n\n // Step 2\n const u = await client.generateCommonSecret(A, B);\n const S = await client.generatePreMasterSecret(a, B, x, u);\n const K = await client.hash(S);\n const M1 = await client.generateClientSessionProof(identity, salt, A, B, K);\n\n const res2 = await $http.post(\n '@auth_ajax/srpAuthenticate',\n {\n identity,\n A: A.toString(16),\n M1: M1.toString(16)\n }\n );\n\n const { proof } = res2.data.data;\n\n const M2 = await client.generateServerSessionProof(A, M1, K);\n\n if (M2 !== hexToBigint(proof)) {\n // Just return\n return;\n }\n\n this.getHiddenInput('srp[M2]').value = M2.toString(16);\n }\n\n disablePasswords() {\n if (this.passwordInput.value) {\n this.passwordInput.disabled = true;\n\n setTimeout(() => {\n this.passwordInput.disabled = false;\n }, 1000);\n }\n\n const inputs = this.el.querySelectorAll('[data-srp-override]');\n\n for (const input of inputs) {\n if (input.value) {\n input.disabled = true;\n\n setTimeout(() => {\n input.disabled = false;\n }, 1000);\n }\n }\n }\n\n createClient(): InstanceType {\n const client = SRPClient.create(\n this.options.prime,\n this.options.generator,\n this.options.key,\n );\n\n client.setSize(this.options.size);\n client.setHasher(this.options.hasher);\n\n return client;\n }\n\n getHiddenInput(name: string) {\n return this.el.querySelector(`[name=\"${name}\"]`)\n || this.createHiddenInput(name);\n }\n\n createHiddenInput(name: string) {\n const input = document.createElement('input');\n\n input.type = 'hidden';\n input.name = name;\n\n this.el.appendChild(input);\n\n return input;\n }\n}\n\nfunction hexToBigint(hex: string) {\n return BigInt(`0x${hex}`);\n}\n\nu.directive('srp-registration', {\n mounted(el, { value }) {\n const options = JSON.parse(value);\n u.module(\n el,\n 'srp.registration',\n (el) => new SRPRegistration(el as HTMLFormElement, options)\n );\n }\n});\n\nu.directive('srp-login', {\n mounted(el, { value }) {\n const options = JSON.parse(value);\n u.module(\n el,\n 'srp.registration',\n (el) => new SRPLogin(el as HTMLFormElement, options)\n );\n }\n});\n"]} \ No newline at end of file +{"version":3,"sources":["srp.ts"],"names":[],"mappings":"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","file":"srp.js","sourcesContent":["import '@main';\nimport type { SRPOptions } from '../types/srp';\n\nconst defaultOptions: Partial = {\n identitySelector: '[data-input-identity]',\n passwordSelector: '[data-input-password]',\n size: 256,\n hasher: 'sha256'\n};\n\nconst $http = u.$http;\n\nclass SRPRegistration {\n identityInput: HTMLInputElement;\n passwordInput: HTMLInputElement;\n saltInput: HTMLInputElement;\n verifierInput: HTMLInputElement;\n\n public submitting = false;\n public disabledInputs = [];\n\n constructor(public el: HTMLFormElement, public options: Partial = {}) {\n this.options = Object.assign({}, defaultOptions, this.options);\n\n this.init();\n }\n\n init() {\n this.identityInput = this.el.querySelector(this.options.identitySelector);\n this.passwordInput = this.el.querySelector(this.options.passwordSelector);\n\n if (!this.identityInput || !this.passwordInput) {\n throw new Error('Identity or password input not found.');\n }\n\n this.el.addEventListener('submit', async (e) => {\n if (!this.submitting) {\n e.stopPropagation();\n e.preventDefault();\n e.stopImmediatePropagation();\n\n await this.register();\n\n this.disablePasswords();\n\n this.submitting = true;\n\n this.el.requestSubmit();\n\n return;\n }\n });\n\n this.el.addEventListener('invalid', () => {\n this.release();\n }, true);\n }\n\n release() {\n this.submitting = false;\n\n for (const disabledInput of this.disabledInputs) {\n disabledInput.disabled = false;\n }\n }\n\n getPasswordInputs() {\n return [\n this.passwordInput,\n ...this.el.querySelectorAll('[data-srp-override]')\n ];\n }\n\n disablePasswords() {\n this.disabledInputs = [];\n\n for (const input of this.getPasswordInputs()) {\n if (input.value && !input.disabled) {\n input.disabled = true;\n\n this.disabledInputs.push(input);\n\n setTimeout(() => {\n input.disabled = false;\n }, 1000);\n }\n }\n }\n\n createClient(): InstanceType {\n const client = SRPClient.create(\n this.options.prime,\n this.options.generator,\n this.options.key,\n );\n\n client.setSize(this.options.size);\n client.setHasher(this.options?.hasher);\n\n return client;\n }\n\n async register() {\n const client = this.createClient();\n\n const identity = this.identityInput.value;\n const password = this.passwordInput.value;\n\n let { salt, verifier } = await client.register(identity, password);\n\n const saltInput = this.getHiddenInput('srp[salt]');\n saltInput.value = salt.toString(16);\n\n const verifierInput = this.getHiddenInput('srp[verifier]');\n verifierInput.value = verifier.toString(16);\n }\n\n getHiddenInput(name: string) {\n return this.el.querySelector(`[name=\"${name}\"]`)\n || this.createHiddenInput(name);\n }\n\n createHiddenInput(name: string) {\n const input = document.createElement('input');\n\n input.type = 'hidden';\n input.name = name;\n\n this.el.appendChild(input);\n\n return input;\n }\n}\n\nclass SRPLogin {\n identityInput: HTMLInputElement;\n passwordInput: HTMLInputElement;\n saltInput: HTMLInputElement;\n verifierInput: HTMLInputElement;\n\n public fallback = false;\n public submitting = false;\n public submitter: HTMLButtonElement;\n\n public disabledInputs = [];\n\n constructor(public el: HTMLFormElement, public options: Partial = {}) {\n this.options = Object.assign({}, defaultOptions, this.options);\n\n this.init();\n }\n\n init() {\n this.identityInput = this.el.querySelector(this.options.identitySelector);\n this.passwordInput = this.el.querySelector(this.options.passwordSelector);\n\n if (!this.identityInput || !this.passwordInput) {\n throw new Error('Identity or password input not found.');\n }\n\n this.el.addEventListener('submit', async (e) => {\n this.submitter = e.submitter as HTMLButtonElement;\n\n if (!this.submitting) {\n e.stopPropagation();\n e.preventDefault();\n e.stopImmediatePropagation();\n\n try {\n await this.auth();\n } catch (e) {\n console.warn(e);\n }\n\n if (!this.fallback) {\n this.disablePasswords();\n }\n\n this.submitting = true;\n\n this.el.requestSubmit();\n\n return;\n }\n });\n\n this.el.addEventListener('invalid', () => {\n this.release();\n }, true);\n }\n\n release() {\n if (this.submitter) {\n this.submitter.disabled = false;\n }\n\n this.submitting = false;\n this.fallback = false;\n this.getHiddenInput('srp[M2]').value = '';\n\n for (const disabledInput of this.disabledInputs) {\n disabledInput.disabled = false;\n }\n }\n\n async auth() {\n if (!this.identityInput.value || !this.passwordInput.value) {\n return;\n }\n\n if (this.submitter) {\n this.submitter.disabled = true;\n }\n\n const identity = this.identityInput.value;\n const password = this.passwordInput.value;\n\n const client = this.createClient();\n\n // Challenge\n const res = await $http.get(\n '@auth_ajax/srpChallenge{?identity}',\n {\n vars: {\n identity\n }\n }\n );\n\n const r = res.data.data;\n\n if (r == null) {\n return;\n }\n\n this.fallback = !!r.fallback;\n this.getHiddenInput('srp[fallback]').value = this.fallback ? '1' : '0';\n\n if (this.fallback) {\n return;\n }\n\n let { salt, B } = r;\n\n // Step1\n salt = hexToBigint(salt);\n B = hexToBigint(B);\n\n // Step 1\n const a = await client.generateRandomSecret();\n const A = await client.generatePublic(a);\n const x = await client.generatePasswordHash(salt, identity, password);\n\n // Step 2\n const u = await client.generateCommonSecret(A, B);\n const S = await client.generatePreMasterSecret(a, B, x, u);\n const K = await client.hash(S);\n const M1 = await client.generateClientSessionProof(identity, salt, A, B, K);\n\n const res2 = await $http.post(\n '@auth_ajax/srpAuthenticate',\n {\n identity,\n A: A.toString(16),\n M1: M1.toString(16)\n }\n );\n\n const { proof } = res2.data.data;\n\n const M2 = await client.generateServerSessionProof(A, M1, K);\n\n if (M2 !== hexToBigint(proof)) {\n // Just return\n return;\n }\n\n this.getHiddenInput('srp[M2]').value = M2.toString(16);\n }\n\n getPasswordInputs() {\n return [\n this.passwordInput,\n ...this.el.querySelectorAll('[data-srp-override]')\n ];\n }\n\n disablePasswords() {\n this.disabledInputs = [];\n\n for (const input of this.getPasswordInputs()) {\n if (input.value && !input.disabled) {\n input.disabled = true;\n\n this.disabledInputs.push(input);\n\n setTimeout(() => {\n input.disabled = false;\n }, 1000);\n }\n }\n }\n\n createClient(): InstanceType {\n const client = SRPClient.create(\n this.options.prime,\n this.options.generator,\n this.options.key,\n );\n\n client.setSize(this.options.size);\n client.setHasher(this.options.hasher);\n\n return client;\n }\n\n getHiddenInput(name: string) {\n return this.el.querySelector(`[name=\"${name}\"]`)\n || this.createHiddenInput(name);\n }\n\n createHiddenInput(name: string) {\n const input = document.createElement('input');\n\n input.type = 'hidden';\n input.name = name;\n\n this.el.appendChild(input);\n\n return input;\n }\n}\n\nfunction hexToBigint(hex: string) {\n return BigInt(`0x${hex}`);\n}\n\nu.directive('srp-registration', {\n mounted(el, { value }) {\n const options = JSON.parse(value);\n u.module(\n el,\n 'srp.registration',\n (el) => new SRPRegistration(el as HTMLFormElement, options)\n );\n }\n});\n\nu.directive('srp-login', {\n mounted(el, { value }) {\n const options = JSON.parse(value);\n u.module(\n el,\n 'srp.registration',\n (el) => new SRPLogin(el as HTMLFormElement, options)\n );\n }\n});\n"]} \ No newline at end of file diff --git a/assets/src/js/srp.ts b/assets/src/js/srp.ts index 5a064fd1..dd6325eb 100644 --- a/assets/src/js/srp.ts +++ b/assets/src/js/srp.ts @@ -17,6 +17,7 @@ class SRPRegistration { verifierInput: HTMLInputElement; public submitting = false; + public disabledInputs = []; constructor(public el: HTMLFormElement, public options: Partial = {}) { this.options = Object.assign({}, defaultOptions, this.options); @@ -51,25 +52,34 @@ class SRPRegistration { }); this.el.addEventListener('invalid', () => { - this.submitting = false; + this.release(); }, true); } - disablePasswords() { - if (this.passwordInput.value) { - this.passwordInput.disabled = true; + release() { + this.submitting = false; - setTimeout(() => { - this.passwordInput.disabled = false; - }, 1000); + for (const disabledInput of this.disabledInputs) { + disabledInput.disabled = false; } + } - const inputs = this.el.querySelectorAll('[data-srp-override]'); + getPasswordInputs() { + return [ + this.passwordInput, + ...this.el.querySelectorAll('[data-srp-override]') + ]; + } + + disablePasswords() { + this.disabledInputs = []; - for (const input of inputs) { - if (input.value) { + for (const input of this.getPasswordInputs()) { + if (input.value && !input.disabled) { input.disabled = true; + this.disabledInputs.push(input); + setTimeout(() => { input.disabled = false; }, 1000); @@ -132,6 +142,8 @@ class SRPLogin { public submitting = false; public submitter: HTMLButtonElement; + public disabledInputs = []; + constructor(public el: HTMLFormElement, public options: Partial = {}) { this.options = Object.assign({}, defaultOptions, this.options); @@ -184,6 +196,11 @@ class SRPLogin { this.submitting = false; this.fallback = false; + this.getHiddenInput('srp[M2]').value = ''; + + for (const disabledInput of this.disabledInputs) { + disabledInput.disabled = false; + } } async auth() { @@ -261,21 +278,22 @@ class SRPLogin { this.getHiddenInput('srp[M2]').value = M2.toString(16); } - disablePasswords() { - if (this.passwordInput.value) { - this.passwordInput.disabled = true; - - setTimeout(() => { - this.passwordInput.disabled = false; - }, 1000); - } + getPasswordInputs() { + return [ + this.passwordInput, + ...this.el.querySelectorAll('[data-srp-override]') + ]; + } - const inputs = this.el.querySelectorAll('[data-srp-override]'); + disablePasswords() { + this.disabledInputs = []; - for (const input of inputs) { - if (input.value) { + for (const input of this.getPasswordInputs()) { + if (input.value && !input.disabled) { input.disabled = true; + this.disabledInputs.push(input); + setTimeout(() => { input.disabled = false; }, 1000); diff --git a/src/Auth/SRP/SRPService.php b/src/Auth/SRP/SRPService.php index 0de90c4e..c6600a31 100644 --- a/src/Auth/SRP/SRPService.php +++ b/src/Auth/SRP/SRPService.php @@ -5,6 +5,7 @@ namespace Lyrasoft\Luna\Auth\SRP; use Brick\Math\BigInteger; +use Lyrasoft\Luna\Entity\User; use Lyrasoft\Luna\Script\SRPScript; use Windwalker\Core\Application\AppContext; use Windwalker\Core\Application\ApplicationInterface; @@ -79,7 +80,7 @@ public function loginDirective(array $options = []): string return HTMLElement::buildAttributes(['uni-srp-login' => json_encode($options)]); } - public function handleRegister(AppContext $app, array $user): array + public function handleRegister(AppContext $app, array|User $user): array|User { if (!$this->isEnabled()) { return $user; @@ -89,7 +90,11 @@ public function handleRegister(AppContext $app, array $user): array $password = static::encodePasswordVerifier($srp['salt'], $srp['verifier']); - $user['password'] = $password; + if ($user instanceof User) { + $user->setPassword($password); + } else { + $user['password'] = $password; + } return $user; } diff --git a/src/Module/Front/Auth/ForgetController.php b/src/Module/Front/Auth/ForgetController.php index ec2b78b4..a61a0d94 100644 --- a/src/Module/Front/Auth/ForgetController.php +++ b/src/Module/Front/Auth/ForgetController.php @@ -6,6 +6,7 @@ use Firebase\JWT\JWT; use Firebase\JWT\Key; +use Lyrasoft\Luna\Auth\SRP\SRPService; use Lyrasoft\Luna\Entity\User; use Lyrasoft\Luna\User\UserService; use Windwalker\Core\Application\AppContext; @@ -16,6 +17,7 @@ use Windwalker\Core\Renderer\RendererService; use Windwalker\Core\Router\Navigator; use Windwalker\Core\Router\RouteUri; +use Windwalker\Crypt\Hasher\PasswordHasherInterface; use Windwalker\ORM\ORM; /** @@ -114,10 +116,12 @@ public function confirm(AppContext $app, UserService $userService, Navigator $na return $nav->to('forget_reset'); } - public function reset(AppContext $app, UserService $userService, ORM $orm, Navigator $nav): RouteUri - { - $password = $app->input('password'); - $password2 = $app->input('password2'); + public function reset( + AppContext $app, + UserService $userService, + ORM $orm, + Navigator $nav + ): RouteUri { $token = $app->input('token'); if (!$token) { @@ -142,14 +146,27 @@ public function reset(AppContext $app, UserService $userService, ORM $orm, Navig throw new ValidateFailException($this->trans('luna.forget.request.message.invalid.token')); } - if ($password !== $password2) { - throw new ValidateFailException($this->trans('luna.forget.reset.message.password.not.match')); + $srpService = $app->retrieve(SRPService::class); + + if ($srpService->isEnabled()) { + $user = $srpService->handleRegister($app, $user); + } else { + $password = $app->input('password'); + $password2 = $app->input('password2'); + + $hasher = $app->retrieve(PasswordHasherInterface::class); + + if ($password !== $password2) { + throw new ValidateFailException($this->trans('luna.forget.reset.message.password.not.match')); + } + + $user->setPassword($hasher->hash($password)); } - $user->setPassword(password_hash($password, PASSWORD_DEFAULT)); $user->setResetToken(''); $user->setLastReset('now'); + $orm->updateOne( User::class, $user diff --git a/src/Module/Front/Auth/ForgetResetView.php b/src/Module/Front/Auth/ForgetResetView.php index 9a3b0345..6ae318fb 100644 --- a/src/Module/Front/Auth/ForgetResetView.php +++ b/src/Module/Front/Auth/ForgetResetView.php @@ -4,12 +4,20 @@ namespace Lyrasoft\Luna\Module\Front\Auth; +use Firebase\JWT\JWT; +use Firebase\JWT\Key; +use Lyrasoft\Luna\Auth\SRP\SRPService; +use Lyrasoft\Luna\Entity\User; +use Lyrasoft\Luna\LunaPackage; +use Lyrasoft\Luna\User\UserService; use Windwalker\Core\Application\AppContext; use Windwalker\Core\Attributes\ViewModel; use Windwalker\Core\Language\TranslatorTrait; use Windwalker\Core\Router\Navigator; use Windwalker\Core\View\View; use Windwalker\Core\View\ViewModelInterface; +use Windwalker\Data\Collection; +use Windwalker\ORM\ORM; /** * The ForgetResetView class. @@ -28,7 +36,7 @@ class ForgetResetView implements ViewModelInterface /** * Constructor. */ - public function __construct(protected Navigator $nav) + public function __construct(protected Navigator $nav, protected SRPService $srp) { // } @@ -51,6 +59,25 @@ public function prepare(AppContext $app, View $view): mixed $view->setTitle($this->trans('luna.reset.form.title')); - return compact('token'); + $identity = ''; + + if ($this->srp->isEnabled()) { + $payload = JWT::decode( + $token, + new Key($app->getSecret(), 'HS256'), + ); + + $email = $payload->email ?? null; + + /** @var User $user */ + $user = $app->retrieve(ORM::class) + ->findOne(User::class, ['email' => (string) $email], Collection::class); + + $loginName = $app->service(LunaPackage::class)->getLoginName(); + + $identity = $user->$loginName; + } + + return compact('token', 'identity'); } } diff --git a/src/Module/Front/Auth/views/forget-reset.blade.php b/src/Module/Front/Auth/views/forget-reset.blade.php index 9e2f1fe8..8408ba43 100644 --- a/src/Module/Front/Auth/views/forget-reset.blade.php +++ b/src/Module/Front/Auth/views/forget-reset.blade.php @@ -16,6 +16,7 @@ * @var $lang LangService The language translation service. */ +use Lyrasoft\Luna\Auth\SRP\SRPService; use Windwalker\Core\Application\AppContext; use Windwalker\Core\Asset\AssetService; use Windwalker\Core\DateTime\ChronosService; @@ -23,6 +24,7 @@ use Windwalker\Core\Router\Navigator; use Windwalker\Core\Router\SystemUri; +$srp = $app->retrieve(SRPService::class); ?> @extends($app->config('luna.view_extends.front.auth') ?? 'global.auth') @@ -32,7 +34,9 @@ action="{{ $nav->to('forget_reset') }}" uni-form-validate method="POST" - enctype="multipart/form-data"> + enctype="multipart/form-data" + {!! $srp->registerDirective() !!} + >
+
diff --git a/src/Module/Front/Registration/Form/RegistrationForm.php b/src/Module/Front/Registration/Form/RegistrationForm.php index 1fde0d2c..3b1ecbe1 100644 --- a/src/Module/Front/Registration/Form/RegistrationForm.php +++ b/src/Module/Front/Registration/Form/RegistrationForm.php @@ -24,7 +24,7 @@ class RegistrationForm implements FieldDefinitionInterface /** * RegistrationForm constructor. */ - public function __construct(#[Ref('user')] protected $config, protected SRPService $SRPService) + public function __construct(#[Ref('user')] protected $config) { } @@ -70,15 +70,14 @@ public function define(Form $form): void ->attr('data-input-password', true) ->autocomplete('new-password'); - if (!$this->SRPService->isEnabled()) { - $form->add('password2', PasswordField::class) - ->label($this->trans('luna.user.field.password.confirm')) - ->attr('data-srp-override', true) - ->attr('data-validate', 'password-confirm') - ->attr('data-confirm-target', '[data-role=password]') - ->attr('data-custom-error-message', $this->trans('luna.message.password.not.match')) - ->autocomplete('new-password'); - } + $form->add('password2', PasswordField::class) + ->label($this->trans('luna.user.field.password.confirm')) + ->required(true) + ->attr('data-srp-override', true) + ->attr('data-validate', 'password-confirm') + ->attr('data-confirm-target', '[data-role=password]') + ->attr('data-custom-error-message', $this->trans('luna.message.password.not.match')) + ->autocomplete('new-password'); }); } }