@vue-skuilder/express 0.1.13-4 → 0.1.13-6
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/routes/auth.d.ts.map +1 -1
- package/dist/routes/auth.js +22 -15
- package/dist/routes/auth.js.map +1 -1
- package/dist/services/email.d.ts.map +1 -1
- package/dist/services/email.js +7 -6
- package/dist/services/email.js.map +1 -1
- package/package.json +3 -3
- package/src/routes/auth.ts +25 -17
- package/src/services/email.ts +8 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/routes/auth.ts"],"names":[],"mappings":"AAYA,QAAA,MAAM,MAAM,4CAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/routes/auth.ts"],"names":[],"mappings":"AAYA,QAAA,MAAM,MAAM,4CAAmB,CAAC;AA6NhC,eAAe,MAAM,CAAC"}
|
package/dist/routes/auth.js
CHANGED
|
@@ -7,16 +7,16 @@ const router = express.Router();
|
|
|
7
7
|
/**
|
|
8
8
|
* POST /auth/send-verification
|
|
9
9
|
* Trigger verification email for a newly created account.
|
|
10
|
-
* Reads email from userdb-{username}/CONFIG.
|
|
11
10
|
*
|
|
12
11
|
* Body params:
|
|
13
12
|
* - username: string (required)
|
|
13
|
+
* - email: string (optional) - If provided, uses this email directly (avoids DB sync race condition)
|
|
14
14
|
* - origin: string (optional) - Frontend origin URL for constructing verification link
|
|
15
15
|
*/
|
|
16
16
|
router.post('/send-verification', (req, res) => {
|
|
17
17
|
void (async () => {
|
|
18
18
|
try {
|
|
19
|
-
const { username, origin } = req.body;
|
|
19
|
+
const { username, email: providedEmail, origin } = req.body;
|
|
20
20
|
if (!username) {
|
|
21
21
|
return res.status(400).json({ ok: false, error: 'Username required' });
|
|
22
22
|
}
|
|
@@ -25,21 +25,28 @@ router.post('/send-verification', (req, res) => {
|
|
|
25
25
|
if (!userDoc) {
|
|
26
26
|
return res.status(404).json({ ok: false, error: 'User not found' });
|
|
27
27
|
}
|
|
28
|
-
//
|
|
29
|
-
|
|
28
|
+
// Use provided email if available, otherwise lookup in database
|
|
29
|
+
let email = providedEmail;
|
|
30
30
|
if (!email) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
email = await getUserEmail(username);
|
|
32
|
+
if (!email) {
|
|
33
|
+
return res.status(400).json({
|
|
34
|
+
ok: false,
|
|
35
|
+
error: 'No email found for user. Please provide email during registration.',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
35
38
|
}
|
|
36
39
|
// Generate verification token (24 hour expiry)
|
|
37
40
|
const token = generateSecureToken();
|
|
38
41
|
const expiresAt = getTokenExpiry(24);
|
|
39
|
-
// Update user doc with token
|
|
42
|
+
// Update user doc with token and email (for password reset lookup)
|
|
40
43
|
userDoc.verificationToken = token;
|
|
41
44
|
userDoc.verificationTokenExpiresAt = expiresAt;
|
|
42
45
|
userDoc.status = 'pending_verification';
|
|
46
|
+
// Save email to _users doc if not already present (enables findUserByEmail)
|
|
47
|
+
if (email && !userDoc.email) {
|
|
48
|
+
userDoc.email = email;
|
|
49
|
+
}
|
|
43
50
|
await updateUserDoc(userDoc);
|
|
44
51
|
// Send verification email with origin for link construction
|
|
45
52
|
await sendVerificationEmail(email, token, origin);
|
|
@@ -157,10 +164,12 @@ router.post('/reset-password', (req, res) => {
|
|
|
157
164
|
isTokenExpired(userDoc.passwordResetTokenExpiresAt)) {
|
|
158
165
|
return res.status(400).json({ ok: false, error: 'Token has expired' });
|
|
159
166
|
}
|
|
160
|
-
//
|
|
161
|
-
// CouchDB
|
|
162
|
-
//
|
|
163
|
-
|
|
167
|
+
// Update password in CouchDB
|
|
168
|
+
// CouchDB has an internal hook that automatically hashes the password
|
|
169
|
+
// when a 'password' field is present in the user document.
|
|
170
|
+
// see https://docs.couchdb.org/en/stable/intro/security.html#password-changing
|
|
171
|
+
// @ts-expect-error writing to metadata field here.
|
|
172
|
+
userDoc.password = newPassword; // Add plain text password field
|
|
164
173
|
// Clear reset token
|
|
165
174
|
userDoc.passwordResetToken = null;
|
|
166
175
|
userDoc.passwordResetTokenExpiresAt = null;
|
|
@@ -168,8 +177,6 @@ router.post('/reset-password', (req, res) => {
|
|
|
168
177
|
logger.info(`Password reset completed for ${userDoc.name}`);
|
|
169
178
|
res.json({
|
|
170
179
|
ok: true,
|
|
171
|
-
// TODO: Remove this warning once password update is implemented
|
|
172
|
-
warning: 'Password reset flow completed, but actual password update not yet implemented',
|
|
173
180
|
});
|
|
174
181
|
}
|
|
175
182
|
catch (error) {
|
package/dist/routes/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/routes/auth.ts"],"names":[],"mappings":"AAAA,OAAO,OAA8B,MAAM,SAAS,CAAC;AACrD,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,YAAY,EACZ,aAAa,GACd,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzF,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACrF,OAAO,MAAM,MAAM,cAAc,CAAC;AAElC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;AAEhC;;;;;;;;GAQG;AACH,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IAChE,KAAK,CAAC,KAAK,IAAI,EAAE;QACf,IAAI,CAAC;YACL,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/routes/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../../src/services/email.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../../src/services/email.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAiCf;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
|
package/dist/services/email.js
CHANGED
|
@@ -17,17 +17,18 @@ export async function sendVerificationEmail(to, token, origin) {
|
|
|
17
17
|
const baseUrl = origin || process.env.APP_URL || 'http://localhost:5173';
|
|
18
18
|
const verificationLink = `${baseUrl}/verify?token=${token}`;
|
|
19
19
|
try {
|
|
20
|
+
const payload = {
|
|
21
|
+
recipientEmail: to,
|
|
22
|
+
recipientName: to.split('@')[0], // Extract name from email (simple approach)
|
|
23
|
+
magicLink: verificationLink,
|
|
24
|
+
supportEmail: process.env.SUPPORT_EMAIL || 'support@example.com',
|
|
25
|
+
};
|
|
20
26
|
const response = await fetch(`${MAILER_SERVICE_URL}/send-verification`, {
|
|
21
27
|
method: 'POST',
|
|
22
28
|
headers: {
|
|
23
29
|
'Content-Type': 'application/json',
|
|
24
30
|
},
|
|
25
|
-
body: JSON.stringify(
|
|
26
|
-
recipientEmail: to,
|
|
27
|
-
recipientName: to.split('@')[0], // Extract name from email (simple approach)
|
|
28
|
-
magicLink: verificationLink,
|
|
29
|
-
supportEmail: process.env.SUPPORT_EMAIL || 'support@example.com',
|
|
30
|
-
}),
|
|
31
|
+
body: JSON.stringify(payload),
|
|
31
32
|
});
|
|
32
33
|
if (!response.ok) {
|
|
33
34
|
const error = await response.json();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email.js","sourceRoot":"","sources":["../../src/services/email.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,cAAc,CAAC;AAElC;;;;GAIG;AAEH,MAAM,kBAAkB,GACtB,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,8BAA8B,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,EAAU,EACV,KAAa,EACb,MAAe;IAEf,gEAAgE;IAChE,MAAM,OAAO,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,uBAAuB,CAAC;IACzE,MAAM,gBAAgB,GAAG,GAAG,OAAO,iBAAiB,KAAK,EAAE,CAAC;IAE5D,IAAI,CAAC;QACH,MAAM,
|
|
1
|
+
{"version":3,"file":"email.js","sourceRoot":"","sources":["../../src/services/email.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.1.13-
|
|
6
|
+
"version": "0.1.13-6",
|
|
7
7
|
"description": "an API",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"type": "module",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"author": "Colin Kennedy",
|
|
34
34
|
"license": "GPL-3.0-or-later",
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@vue-skuilder/common": "^0.1.13-
|
|
37
|
-
"@vue-skuilder/db": "^0.1.13-
|
|
36
|
+
"@vue-skuilder/common": "^0.1.13-6",
|
|
37
|
+
"@vue-skuilder/db": "^0.1.13-6",
|
|
38
38
|
"axios": "^1.7.4",
|
|
39
39
|
"cookie-parser": "^1.4.7",
|
|
40
40
|
"cors": "^2.8.5",
|
package/src/routes/auth.ts
CHANGED
|
@@ -15,16 +15,16 @@ const router = express.Router();
|
|
|
15
15
|
/**
|
|
16
16
|
* POST /auth/send-verification
|
|
17
17
|
* Trigger verification email for a newly created account.
|
|
18
|
-
* Reads email from userdb-{username}/CONFIG.
|
|
19
18
|
*
|
|
20
19
|
* Body params:
|
|
21
20
|
* - username: string (required)
|
|
21
|
+
* - email: string (optional) - If provided, uses this email directly (avoids DB sync race condition)
|
|
22
22
|
* - origin: string (optional) - Frontend origin URL for constructing verification link
|
|
23
23
|
*/
|
|
24
24
|
router.post('/send-verification', (req: Request, res: Response) => {
|
|
25
25
|
void (async () => {
|
|
26
26
|
try {
|
|
27
|
-
const { username, origin } = req.body;
|
|
27
|
+
const { username, email: providedEmail, origin } = req.body;
|
|
28
28
|
|
|
29
29
|
if (!username) {
|
|
30
30
|
return res.status(400).json({ ok: false, error: 'Username required' });
|
|
@@ -36,24 +36,32 @@ router.post('/send-verification', (req: Request, res: Response) => {
|
|
|
36
36
|
return res.status(404).json({ ok: false, error: 'User not found' });
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
//
|
|
40
|
-
|
|
39
|
+
// Use provided email if available, otherwise lookup in database
|
|
40
|
+
let email = providedEmail;
|
|
41
41
|
if (!email) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
email = await getUserEmail(username);
|
|
43
|
+
if (!email) {
|
|
44
|
+
return res.status(400).json({
|
|
45
|
+
ok: false,
|
|
46
|
+
error: 'No email found for user. Please provide email during registration.',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
// Generate verification token (24 hour expiry)
|
|
49
52
|
const token = generateSecureToken();
|
|
50
53
|
const expiresAt = getTokenExpiry(24);
|
|
51
54
|
|
|
52
|
-
// Update user doc with token
|
|
55
|
+
// Update user doc with token and email (for password reset lookup)
|
|
53
56
|
userDoc.verificationToken = token;
|
|
54
57
|
userDoc.verificationTokenExpiresAt = expiresAt;
|
|
55
58
|
userDoc.status = 'pending_verification';
|
|
56
59
|
|
|
60
|
+
// Save email to _users doc if not already present (enables findUserByEmail)
|
|
61
|
+
if (email && !userDoc.email) {
|
|
62
|
+
userDoc.email = email as string;
|
|
63
|
+
}
|
|
64
|
+
|
|
57
65
|
await updateUserDoc(userDoc);
|
|
58
66
|
|
|
59
67
|
// Send verification email with origin for link construction
|
|
@@ -194,12 +202,14 @@ router.post('/reset-password', (req: Request, res: Response) => {
|
|
|
194
202
|
return res.status(400).json({ ok: false, error: 'Token has expired' });
|
|
195
203
|
}
|
|
196
204
|
|
|
197
|
-
//
|
|
198
|
-
// CouchDB
|
|
199
|
-
//
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
205
|
+
// Update password in CouchDB
|
|
206
|
+
// CouchDB has an internal hook that automatically hashes the password
|
|
207
|
+
// when a 'password' field is present in the user document.
|
|
208
|
+
// see https://docs.couchdb.org/en/stable/intro/security.html#password-changing
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
// @ts-expect-error writing to metadata field here.
|
|
212
|
+
userDoc.password = newPassword as string; // Add plain text password field
|
|
203
213
|
|
|
204
214
|
// Clear reset token
|
|
205
215
|
userDoc.passwordResetToken = null;
|
|
@@ -210,8 +220,6 @@ router.post('/reset-password', (req: Request, res: Response) => {
|
|
|
210
220
|
logger.info(`Password reset completed for ${userDoc.name}`);
|
|
211
221
|
res.json({
|
|
212
222
|
ok: true,
|
|
213
|
-
// TODO: Remove this warning once password update is implemented
|
|
214
|
-
warning: 'Password reset flow completed, but actual password update not yet implemented',
|
|
215
223
|
});
|
|
216
224
|
} catch (error) {
|
|
217
225
|
logger.error('Error resetting password:', error);
|
package/src/services/email.ts
CHANGED
|
@@ -26,17 +26,19 @@ export async function sendVerificationEmail(
|
|
|
26
26
|
const verificationLink = `${baseUrl}/verify?token=${token}`;
|
|
27
27
|
|
|
28
28
|
try {
|
|
29
|
+
const payload = {
|
|
30
|
+
recipientEmail: to,
|
|
31
|
+
recipientName: to.split('@')[0], // Extract name from email (simple approach)
|
|
32
|
+
magicLink: verificationLink,
|
|
33
|
+
supportEmail: process.env.SUPPORT_EMAIL || 'support@example.com',
|
|
34
|
+
};
|
|
35
|
+
|
|
29
36
|
const response = await fetch(`${MAILER_SERVICE_URL}/send-verification`, {
|
|
30
37
|
method: 'POST',
|
|
31
38
|
headers: {
|
|
32
39
|
'Content-Type': 'application/json',
|
|
33
40
|
},
|
|
34
|
-
body: JSON.stringify(
|
|
35
|
-
recipientEmail: to,
|
|
36
|
-
recipientName: to.split('@')[0], // Extract name from email (simple approach)
|
|
37
|
-
magicLink: verificationLink,
|
|
38
|
-
supportEmail: process.env.SUPPORT_EMAIL || 'support@example.com',
|
|
39
|
-
}),
|
|
41
|
+
body: JSON.stringify(payload),
|
|
40
42
|
});
|
|
41
43
|
|
|
42
44
|
if (!response.ok) {
|
|
@@ -49,7 +51,6 @@ export async function sendVerificationEmail(
|
|
|
49
51
|
logger.info(`Verification email sent to ${to} via mailer service`);
|
|
50
52
|
} catch (error) {
|
|
51
53
|
logger.error(`Failed to send verification email to ${to}:`, error);
|
|
52
|
-
|
|
53
54
|
throw error;
|
|
54
55
|
}
|
|
55
56
|
}
|