@vue-skuilder/common-ui 0.2.19 → 0.2.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/index.css +1 -1
- package/dist/common-ui.es.js +53 -8
- package/dist/common-ui.es.js.map +1 -1
- package/dist/common-ui.umd.js +5 -5
- package/dist/common-ui.umd.js.map +1 -1
- package/dist/components/auth/UserLogin.vue.d.ts.map +1 -1
- package/dist/components/auth/UserRegistration.vue.d.ts.map +1 -1
- package/dist/components/auth/index.d.ts +1 -1
- package/dist/components/auth/index.d.ts.map +1 -1
- package/dist/services/authAPI.d.ts +10 -0
- package/dist/services/authAPI.d.ts.map +1 -1
- package/dist/stores/useAuthStore.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/components/auth/UserLogin.vue +23 -5
- package/src/components/auth/UserRegistration.vue +3 -4
- package/src/components/auth/index.ts +2 -0
- package/src/services/authAPI.ts +53 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserLogin.vue.d.ts","sourceRoot":"","sources":["../../../src/components/auth/UserLogin.vue"],"names":[],"mappings":"AA2DA;
|
|
1
|
+
{"version":3,"file":"UserLogin.vue.d.ts","sourceRoot":"","sources":["../../../src/components/auth/UserLogin.vue"],"names":[],"mappings":"AA2DA;AAyNA,UAAU,KAAK;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAmID,iBAAS,cAAc;WAuPT,OAAO,IAA6B;;mCAVV,GAAG;;;;EAe1C;AAqBD,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAC9D,QAAA,MAAM,eAAe;;;;;;;;;gBAtZN,MAAM;6EA+ZnB,CAAC;wBACkB,uBAAuB,CAAC,OAAO,eAAe,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAAnG,wBAAoG;AAapG,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IACxC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KAEV,CAAA;CACD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserRegistration.vue.d.ts","sourceRoot":"","sources":["../../../src/components/auth/UserRegistration.vue"],"names":[],"mappings":"AA8EA;AAAA,
|
|
1
|
+
{"version":3,"file":"UserRegistration.vue.d.ts","sourceRoot":"","sources":["../../../src/components/auth/UserRegistration.vue"],"names":[],"mappings":"AA8EA;AAAA,OAgSO,EAAmB,QAAQ,EAAE,MAAM,KAAK,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,MAAM,EAAO,MAAM,sBAAsB,CAAC;;;cAU3B,QAAQ,CAAC,CAAC,OAAO,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE,KAAK,IAAI,CAAC;;;;;;;;;;;;;;;;;;UAuBrD,eAAe,GAAG,IAAI;WACO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBAqR5C,CAAC;;;;;;;;;;;;wBAqCJ,CAAC;yBAAuB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBArCtB,CAAC;;;;;;;;;;;;wBAqCJ,CAAC;yBAAuB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBArCtB,CAAC;;;;;;;;;;;;wBAqCJ,CAAC;yBAAuB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBArCtB,CAAC;;;;;;;;;;;;wBAqCJ,CAAC;yBAAuB,CAAC;;;;;;;;;;;;;;;;;yBAjTV,OAAO;;;;;qBASX,MAAM;2BAGA,MAAM;;;;;;;;cA7CT,QAAQ,CAAC,CAAC,OAAO,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE,KAAK,IAAI,CAAC;;;;;;;AALzE,wBAoMG"}
|
|
@@ -5,5 +5,5 @@ export { default as UserLoginAndRegistrationContainer } from './UserLoginAndRegi
|
|
|
5
5
|
export { default as VerifyEmail } from './VerifyEmail.vue';
|
|
6
6
|
export { default as RequestPasswordReset } from './RequestPasswordReset.vue';
|
|
7
7
|
export { default as ResetPassword } from './ResetPassword.vue';
|
|
8
|
-
export { sendVerificationEmail, verifyEmail, getUserStatus, requestPasswordReset, resetPassword, type AuthResponse, type VerifyEmailResponse, type UserStatusResponse, } from '../../services/authAPI';
|
|
8
|
+
export { sendVerificationEmail, verifyEmail, getUserStatus, resolveLoginIdentifier, requestPasswordReset, resetPassword, type AuthResponse, type VerifyEmailResponse, type UserStatusResponse, type ResolveLoginResponse, } from '../../services/authAPI';
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/auth/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,iCAAiC,EAAE,MAAM,yCAAyC,CAAC;AAGvG,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAG/D,OAAO,EACL,qBAAqB,EACrB,WAAW,EACX,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/auth/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,iCAAiC,EAAE,MAAM,yCAAyC,CAAC;AAGvG,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAG/D,OAAO,EACL,qBAAqB,EACrB,WAAW,EACX,aAAa,EACb,sBAAsB,EACtB,oBAAoB,EACpB,aAAa,EACb,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,GAC1B,MAAM,wBAAwB,CAAC"}
|
|
@@ -30,6 +30,9 @@ export interface UserStatusResponse extends AuthResponse {
|
|
|
30
30
|
email?: string | null;
|
|
31
31
|
entitlements?: UserEntitlements;
|
|
32
32
|
}
|
|
33
|
+
export interface ResolveLoginResponse extends AuthResponse {
|
|
34
|
+
username?: string;
|
|
35
|
+
}
|
|
33
36
|
/**
|
|
34
37
|
* Triggers verification email send for a newly created account.
|
|
35
38
|
*
|
|
@@ -44,6 +47,13 @@ export declare function sendVerificationEmail(username: string, email: string, o
|
|
|
44
47
|
* Verify user email using token from magic link.
|
|
45
48
|
*/
|
|
46
49
|
export declare function verifyEmail(token: string): Promise<VerifyEmailResponse>;
|
|
50
|
+
/**
|
|
51
|
+
* Resolve a login identifier (username OR email) to a couch username, gated on
|
|
52
|
+
* the correct password. Returns the username only on success; every failure is
|
|
53
|
+
* a uniform "invalid credentials" (no account-enumeration leak). Used by the
|
|
54
|
+
* login form before calling user.login() when the identifier is an email.
|
|
55
|
+
*/
|
|
56
|
+
export declare function resolveLoginIdentifier(identifier: string, password: string): Promise<ResolveLoginResponse>;
|
|
47
57
|
/**
|
|
48
58
|
* Get current user's account status (verification status, email).
|
|
49
59
|
* Requires valid AuthSession cookie.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authAPI.d.ts","sourceRoot":"","sources":["../../src/services/authAPI.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,mBAAmB,CAAC,EAAE;YACpB,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;SACxB,CAAC;KACH;CACF;AAgCD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAoB,SAAQ,YAAY;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAE3D,MAAM,WAAW,kBAAmB,SAAQ,YAAY;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,sBAAsB,GAAG,UAAU,GAAG,WAAW,CAAC;IAC3D,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,CAAC,EAAE,gBAAgB,CAAC;CACjC;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,CAAC,CA+BvB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,
|
|
1
|
+
{"version":3,"file":"authAPI.d.ts","sourceRoot":"","sources":["../../src/services/authAPI.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,mBAAmB,CAAC,EAAE;YACpB,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;SACxB,CAAC;KACH;CACF;AAgCD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAoB,SAAQ,YAAY;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAE3D,MAAM,WAAW,kBAAmB,SAAQ,YAAY;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,sBAAsB,GAAG,UAAU,GAAG,WAAW,CAAC;IAC3D,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,CAAC,EAAE,gBAAgB,CAAC;CACjC;AAED,MAAM,WAAW,oBAAqB,SAAQ,YAAY;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,CAAC,CA+BvB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA+B7E;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,oBAAoB,CAAC,CA6B/B;AAED;;;GAGG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAsBjE;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,CAAC,CA4BvB;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,YAAY,CAAC,CAuBvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAuthStore.d.ts","sourceRoot":"","sources":["../../src/stores/useAuthStore.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGjE,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,eAAe,GAAG,SAAS,CAAC;IACnC,oBAAoB,EAAE;QACpB,IAAI,EAAE,OAAO,CAAC;QACd,QAAQ,EAAE,OAAO,CAAC;QAClB,aAAa,EAAE,OAAO,CAAC;QACvB,eAAe,EAAE,OAAO,CAAC;KAC1B,CAAC;IACF,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAiB3E;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"useAuthStore.d.ts","sourceRoot":"","sources":["../../src/stores/useAuthStore.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGjE,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,eAAe,GAAG,SAAS,CAAC;IACnC,oBAAoB,EAAE;QACpB,IAAI,EAAE,OAAO,CAAC;QACd,QAAQ,EAAE,OAAO,CAAC;QAClB,aAAa,EAAE,OAAO,CAAC;QACvB,eAAe,EAAE,OAAO,CAAC;KAC1B,CAAC;IACF,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAiB3E;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAgF2vkB,CAAC;;;;;;;;;;;;oBAAm0D,CAAC;qBAAuB,CAAC;;;;;;;kBA3GvmoB,OAAO;sBACH,OAAO;2BACF,OAAO;6BACL,OAAO;;wBAEV,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAsG2vkB,CAAC;;;;;;;;;;;;oBAAm0D,CAAC;qBAAuB,CAAC;;;;;;;kBA3GvmoB,OAAO;sBACH,OAAO;2BACF,OAAO;6BACL,OAAO;;wBAEV,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAsG2vkB,CAAC;;;;;;;;;;;;oBAAm0D,CAAC;qBAAuB,CAAC;;;;;;;kBA3GvmoB,OAAO;sBACH,OAAO;2BACF,OAAO;6BACL,OAAO;;wBAEV,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAsG2vkB,CAAC;;;;;;;;;;;;oBAAm0D,CAAC;qBAAuB,CAAC;;;;;;;;;yBA1CtloB,OAAO;uBAIT,OAAO;;;;;EAqC/B,CAAC"}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.2.
|
|
6
|
+
"version": "0.2.21",
|
|
7
7
|
"sideEffects": false,
|
|
8
8
|
"main": "./dist/common-ui.umd.js",
|
|
9
9
|
"module": "./dist/common-ui.es.js",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"@highlightjs/vue-plugin": "^2.1.2",
|
|
35
35
|
"@mdi/font": "^7.3.67",
|
|
36
36
|
"@vojtechlanka/vue-tags-input": "^3",
|
|
37
|
-
"@vue-skuilder/common": "0.2.
|
|
38
|
-
"@vue-skuilder/db": "0.2.
|
|
37
|
+
"@vue-skuilder/common": "0.2.21",
|
|
38
|
+
"@vue-skuilder/db": "0.2.21",
|
|
39
39
|
"highlight.js": "^11.0.1",
|
|
40
40
|
"marked": "^15.0.6",
|
|
41
41
|
"moment": "^2.29.4",
|
|
@@ -71,5 +71,5 @@
|
|
|
71
71
|
"vite-plugin-dts": "^4.5.3",
|
|
72
72
|
"vitest": "^4.1.0"
|
|
73
73
|
},
|
|
74
|
-
"stableVersion": "0.2.
|
|
74
|
+
"stableVersion": "0.2.21"
|
|
75
75
|
}
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
<v-form onsubmit="return false;" @submit.prevent="login">
|
|
7
7
|
<v-text-field
|
|
8
8
|
id=""
|
|
9
|
-
v-model="
|
|
9
|
+
v-model="identifier"
|
|
10
10
|
autofocus
|
|
11
11
|
name="username"
|
|
12
|
-
label="Username"
|
|
12
|
+
label="Username or email"
|
|
13
13
|
prepend-icon="mdi-account-circle"
|
|
14
14
|
></v-text-field>
|
|
15
15
|
<v-text-field
|
|
@@ -67,6 +67,7 @@ import { Status } from '@vue-skuilder/common';
|
|
|
67
67
|
import { User } from '@vue-skuilder/db';
|
|
68
68
|
import { getCurrentUser, useAuthStore } from '../../stores/useAuthStore';
|
|
69
69
|
import { useConfigStore } from '../../stores/useConfigStore';
|
|
70
|
+
import { resolveLoginIdentifier } from '../../services/authAPI';
|
|
70
71
|
|
|
71
72
|
// Define props
|
|
72
73
|
interface Props {
|
|
@@ -89,7 +90,8 @@ const route = useRoute();
|
|
|
89
90
|
const authStore = useAuthStore();
|
|
90
91
|
const configStore = useConfigStore();
|
|
91
92
|
|
|
92
|
-
|
|
93
|
+
// Holds a username OR an email address (see login()).
|
|
94
|
+
const identifier = ref('');
|
|
93
95
|
const password = ref('');
|
|
94
96
|
const passwordVisible = ref(false);
|
|
95
97
|
const awaitingResponse = ref(false);
|
|
@@ -120,7 +122,7 @@ const initBadLogin = () => {
|
|
|
120
122
|
const login = async () => {
|
|
121
123
|
awaitingResponse.value = true;
|
|
122
124
|
log('Starting login attempt');
|
|
123
|
-
log(`Login attempt for
|
|
125
|
+
log(`Login attempt for identifier: ${identifier.value}`);
|
|
124
126
|
|
|
125
127
|
try {
|
|
126
128
|
log('Attempting to get User instance');
|
|
@@ -128,7 +130,23 @@ const login = async () => {
|
|
|
128
130
|
user.value = await getCurrentUser();
|
|
129
131
|
log('Got User instance, attempting login');
|
|
130
132
|
|
|
131
|
-
|
|
133
|
+
// Couch _session authenticates by username only. When the identifier is an
|
|
134
|
+
// email, resolve it to the account username first — server-side and gated
|
|
135
|
+
// on the correct password, so it can't be used to enumerate accounts. A
|
|
136
|
+
// plain username is passed straight through.
|
|
137
|
+
let loginName = identifier.value;
|
|
138
|
+
if (identifier.value.includes('@')) {
|
|
139
|
+
const resolved = await resolveLoginIdentifier(identifier.value, password.value);
|
|
140
|
+
if (!resolved.ok || !resolved.username) {
|
|
141
|
+
log('Email identifier did not resolve (bad credentials)');
|
|
142
|
+
initBadLogin();
|
|
143
|
+
awaitingResponse.value = false;
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
loginName = resolved.username;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
await user.value.login(loginName, password.value);
|
|
132
150
|
log('Login successful');
|
|
133
151
|
|
|
134
152
|
// load user config
|
|
@@ -209,12 +209,11 @@ Author: ${this.author}
|
|
|
209
209
|
this.authStore.loginAndRegistration.init = false;
|
|
210
210
|
this.authStore.loginAndRegistration.init = true;
|
|
211
211
|
|
|
212
|
-
//
|
|
212
|
+
// Send verification email if an address was provided. The address
|
|
213
|
+
// is persisted to the _users doc by send-verification (the single
|
|
214
|
+
// source of truth); no separate CONFIG.email copy is kept.
|
|
213
215
|
if (this.email) {
|
|
214
216
|
try {
|
|
215
|
-
const currentUser = await getCurrentUser();
|
|
216
|
-
await currentUser.setConfig({ email: this.email });
|
|
217
|
-
|
|
218
217
|
// Trigger verification email send with current origin
|
|
219
218
|
const origin = typeof window !== 'undefined' ? window.location.origin : undefined;
|
|
220
219
|
const verificationResult = await sendVerificationEmail(this.username, this.email, origin);
|
|
@@ -14,9 +14,11 @@ export {
|
|
|
14
14
|
sendVerificationEmail,
|
|
15
15
|
verifyEmail,
|
|
16
16
|
getUserStatus,
|
|
17
|
+
resolveLoginIdentifier,
|
|
17
18
|
requestPasswordReset,
|
|
18
19
|
resetPassword,
|
|
19
20
|
type AuthResponse,
|
|
20
21
|
type VerifyEmailResponse,
|
|
21
22
|
type UserStatusResponse,
|
|
23
|
+
type ResolveLoginResponse,
|
|
22
24
|
} from '../../services/authAPI';
|
package/src/services/authAPI.ts
CHANGED
|
@@ -68,6 +68,10 @@ export interface UserStatusResponse extends AuthResponse {
|
|
|
68
68
|
entitlements?: UserEntitlements;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
export interface ResolveLoginResponse extends AuthResponse {
|
|
72
|
+
username?: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
71
75
|
/**
|
|
72
76
|
* Triggers verification email send for a newly created account.
|
|
73
77
|
*
|
|
@@ -127,9 +131,57 @@ export async function verifyEmail(token: string): Promise<VerifyEmailResponse> {
|
|
|
127
131
|
});
|
|
128
132
|
|
|
129
133
|
if (!response.ok) {
|
|
134
|
+
// Prefer the server's explanatory message (expired token, email already
|
|
135
|
+
// verified on another account, …) over a bare HTTP status.
|
|
136
|
+
let serverError: string | undefined;
|
|
137
|
+
try {
|
|
138
|
+
serverError = (await response.json())?.error;
|
|
139
|
+
} catch {
|
|
140
|
+
// non-JSON body — fall through to the generic message
|
|
141
|
+
}
|
|
130
142
|
return {
|
|
131
143
|
ok: false,
|
|
132
|
-
error: `HTTP ${response.status}: ${response.statusText}`,
|
|
144
|
+
error: serverError || `HTTP ${response.status}: ${response.statusText}`,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return await response.json();
|
|
149
|
+
} catch (error) {
|
|
150
|
+
return {
|
|
151
|
+
ok: false,
|
|
152
|
+
error: error instanceof Error ? error.message : 'Network error',
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Resolve a login identifier (username OR email) to a couch username, gated on
|
|
159
|
+
* the correct password. Returns the username only on success; every failure is
|
|
160
|
+
* a uniform "invalid credentials" (no account-enumeration leak). Used by the
|
|
161
|
+
* login form before calling user.login() when the identifier is an email.
|
|
162
|
+
*/
|
|
163
|
+
export async function resolveLoginIdentifier(
|
|
164
|
+
identifier: string,
|
|
165
|
+
password: string
|
|
166
|
+
): Promise<ResolveLoginResponse> {
|
|
167
|
+
try {
|
|
168
|
+
const response = await fetch(`${getApiBase()}/auth/resolve-login`, {
|
|
169
|
+
method: 'POST',
|
|
170
|
+
headers: { 'Content-Type': 'application/json' },
|
|
171
|
+
credentials: 'include',
|
|
172
|
+
body: JSON.stringify({ identifier, password }),
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
if (!response.ok) {
|
|
176
|
+
let serverError: string | undefined;
|
|
177
|
+
try {
|
|
178
|
+
serverError = (await response.json())?.error;
|
|
179
|
+
} catch {
|
|
180
|
+
// non-JSON body — fall through to the generic message
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
ok: false,
|
|
184
|
+
error: serverError || `HTTP ${response.status}: ${response.statusText}`,
|
|
133
185
|
};
|
|
134
186
|
}
|
|
135
187
|
|