payload 3.79.0 → 3.79.1
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/auth/endpoints/forgotPassword.d.ts.map +1 -1
- package/dist/auth/endpoints/forgotPassword.js +0 -2
- package/dist/auth/endpoints/forgotPassword.js.map +1 -1
- package/dist/auth/extractJWT.d.ts.map +1 -1
- package/dist/auth/extractJWT.js +18 -4
- package/dist/auth/extractJWT.js.map +1 -1
- package/dist/auth/operations/forgotPassword.d.ts.map +1 -1
- package/dist/auth/operations/forgotPassword.js +5 -4
- package/dist/auth/operations/forgotPassword.js.map +1 -1
- package/dist/auth/operations/me.js +5 -5
- package/dist/auth/operations/me.js.map +1 -1
- package/dist/auth/sendVerificationEmail.d.ts.map +1 -1
- package/dist/auth/sendVerificationEmail.js +5 -4
- package/dist/auth/sendVerificationEmail.js.map +1 -1
- package/dist/config/orderable/index.d.ts +2 -2
- package/dist/config/orderable/index.d.ts.map +1 -1
- package/dist/config/orderable/index.js +60 -34
- package/dist/config/orderable/index.js.map +1 -1
- package/dist/config/orderable/utils/buildJoinScopeWhere.d.ts +10 -0
- package/dist/config/orderable/utils/buildJoinScopeWhere.d.ts.map +1 -0
- package/dist/config/orderable/utils/buildJoinScopeWhere.js +43 -0
- package/dist/config/orderable/utils/buildJoinScopeWhere.js.map +1 -0
- package/dist/config/orderable/utils/getJoinScopeContext.d.ts +16 -0
- package/dist/config/orderable/utils/getJoinScopeContext.d.ts.map +1 -0
- package/dist/config/orderable/utils/getJoinScopeContext.js +42 -0
- package/dist/config/orderable/utils/getJoinScopeContext.js.map +1 -0
- package/dist/config/orderable/utils/getJoinScopeWhereFromDocData.d.ts +12 -0
- package/dist/config/orderable/utils/getJoinScopeWhereFromDocData.d.ts.map +1 -0
- package/dist/config/orderable/utils/getJoinScopeWhereFromDocData.js +18 -0
- package/dist/config/orderable/utils/getJoinScopeWhereFromDocData.js.map +1 -0
- package/dist/config/orderable/utils/getValueAtPath.d.ts +5 -0
- package/dist/config/orderable/utils/getValueAtPath.d.ts.map +1 -0
- package/dist/config/orderable/utils/getValueAtPath.js +18 -0
- package/dist/config/orderable/utils/getValueAtPath.js.map +1 -0
- package/dist/config/orderable/utils/resolvePendingTargetKey.d.ts +13 -0
- package/dist/config/orderable/utils/resolvePendingTargetKey.d.ts.map +1 -0
- package/dist/config/orderable/utils/resolvePendingTargetKey.js +24 -0
- package/dist/config/orderable/utils/resolvePendingTargetKey.js.map +1 -0
- package/dist/config/types.d.ts +1 -1
- package/dist/config/types.js.map +1 -1
- package/dist/database/getLocalizedPaths.d.ts.map +1 -1
- package/dist/database/getLocalizedPaths.js +2 -1
- package/dist/database/getLocalizedPaths.js.map +1 -1
- package/dist/database/queryValidation/validateQueryPaths.js +1 -1
- package/dist/database/queryValidation/validateQueryPaths.js.map +1 -1
- package/dist/database/queryValidation/validateSearchParams.d.ts.map +1 -1
- package/dist/database/queryValidation/validateSearchParams.js +2 -1
- package/dist/database/queryValidation/validateSearchParams.js.map +1 -1
- package/dist/database/sanitizeJoinQuery.d.ts.map +1 -1
- package/dist/database/sanitizeJoinQuery.js +6 -0
- package/dist/database/sanitizeJoinQuery.js.map +1 -1
- package/dist/exports/shared.d.ts +1 -0
- package/dist/exports/shared.d.ts.map +1 -1
- package/dist/exports/shared.js +1 -0
- package/dist/exports/shared.js.map +1 -1
- package/dist/fields/validations.js +1 -1
- package/dist/fields/validations.js.map +1 -1
- package/dist/fields/validations.spec.js +25 -0
- package/dist/fields/validations.spec.js.map +1 -1
- package/dist/index.bundled.d.ts +8 -5
- package/dist/types/constants.d.ts +5 -0
- package/dist/types/constants.d.ts.map +1 -1
- package/dist/types/constants.js +4 -0
- package/dist/types/constants.js.map +1 -1
- package/dist/uploads/endpoints/getFile.d.ts.map +1 -1
- package/dist/uploads/endpoints/getFile.js +7 -1
- package/dist/uploads/endpoints/getFile.js.map +1 -1
- package/dist/uploads/endpoints/getFileFromURL.d.ts.map +1 -1
- package/dist/uploads/endpoints/getFileFromURL.js +67 -28
- package/dist/uploads/endpoints/getFileFromURL.js.map +1 -1
- package/dist/uploads/getExternalFile.d.ts.map +1 -1
- package/dist/uploads/getExternalFile.js +3 -0
- package/dist/uploads/getExternalFile.js.map +1 -1
- package/dist/uploads/safeFetch.d.ts +1 -1
- package/dist/uploads/safeFetch.d.ts.map +1 -1
- package/dist/uploads/safeFetch.js.map +1 -1
- package/dist/utilities/configToJSONSchema.d.ts +7 -3
- package/dist/utilities/configToJSONSchema.d.ts.map +1 -1
- package/dist/utilities/configToJSONSchema.js +23 -33
- package/dist/utilities/configToJSONSchema.js.map +1 -1
- package/dist/utilities/configToJSONSchema.spec.js +75 -1
- package/dist/utilities/configToJSONSchema.spec.js.map +1 -1
- package/dist/utilities/getRequestOrigin.d.ts +10 -0
- package/dist/utilities/getRequestOrigin.d.ts.map +1 -0
- package/dist/utilities/getRequestOrigin.js +50 -0
- package/dist/utilities/getRequestOrigin.js.map +1 -0
- package/dist/utilities/getRequestOrigin.spec.js +151 -0
- package/dist/utilities/getRequestOrigin.spec.js.map +1 -0
- package/dist/utilities/sanitizeUrl.d.ts +7 -0
- package/dist/utilities/sanitizeUrl.d.ts.map +1 -0
- package/dist/utilities/sanitizeUrl.js +28 -0
- package/dist/utilities/sanitizeUrl.js.map +1 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forgotPassword.d.ts","sourceRoot":"","sources":["../../../src/auth/endpoints/forgotPassword.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAM3D,eAAO,MAAM,qBAAqB,EAAE,
|
|
1
|
+
{"version":3,"file":"forgotPassword.d.ts","sourceRoot":"","sources":["../../../src/auth/endpoints/forgotPassword.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAM3D,eAAO,MAAM,qBAAqB,EAAE,cAgCnC,CAAA"}
|
|
@@ -14,8 +14,6 @@ export const forgotPasswordHandler = async (req)=>{
|
|
|
14
14
|
await forgotPasswordOperation({
|
|
15
15
|
collection,
|
|
16
16
|
data: authData,
|
|
17
|
-
disableEmail: Boolean(req.data?.disableEmail),
|
|
18
|
-
expiration: typeof req.data?.expiration === 'number' ? req.data.expiration : undefined,
|
|
19
17
|
req
|
|
20
18
|
});
|
|
21
19
|
return Response.json({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/auth/endpoints/forgotPassword.ts"],"sourcesContent":["import { status as httpStatus } from 'http-status'\n\nimport type { PayloadHandler } from '../../config/types.js'\n\nimport { getRequestCollection } from '../../utilities/getRequestEntity.js'\nimport { headersWithCors } from '../../utilities/headersWithCors.js'\nimport { forgotPasswordOperation } from '../operations/forgotPassword.js'\n\nexport const forgotPasswordHandler: PayloadHandler = async (req) => {\n const { t } = req\n\n const collection = getRequestCollection(req)\n\n const authData = collection.config.auth?.loginWithUsername\n ? {\n email: typeof req.data?.email === 'string' ? req.data.email : '',\n username: typeof req.data?.username === 'string' ? req.data.username : '',\n }\n : {\n email: typeof req.data?.email === 'string' ? req.data.email : '',\n }\n\n await forgotPasswordOperation({\n collection,\n data: authData,\n
|
|
1
|
+
{"version":3,"sources":["../../../src/auth/endpoints/forgotPassword.ts"],"sourcesContent":["import { status as httpStatus } from 'http-status'\n\nimport type { PayloadHandler } from '../../config/types.js'\n\nimport { getRequestCollection } from '../../utilities/getRequestEntity.js'\nimport { headersWithCors } from '../../utilities/headersWithCors.js'\nimport { forgotPasswordOperation } from '../operations/forgotPassword.js'\n\nexport const forgotPasswordHandler: PayloadHandler = async (req) => {\n const { t } = req\n\n const collection = getRequestCollection(req)\n\n const authData = collection.config.auth?.loginWithUsername\n ? {\n email: typeof req.data?.email === 'string' ? req.data.email : '',\n username: typeof req.data?.username === 'string' ? req.data.username : '',\n }\n : {\n email: typeof req.data?.email === 'string' ? req.data.email : '',\n }\n\n await forgotPasswordOperation({\n collection,\n data: authData,\n req,\n })\n\n return Response.json(\n {\n message: t('general:success'),\n },\n {\n headers: headersWithCors({\n headers: new Headers(),\n req,\n }),\n status: httpStatus.OK,\n },\n )\n}\n"],"names":["status","httpStatus","getRequestCollection","headersWithCors","forgotPasswordOperation","forgotPasswordHandler","req","t","collection","authData","config","auth","loginWithUsername","email","data","username","Response","json","message","headers","Headers","OK"],"mappings":"AAAA,SAASA,UAAUC,UAAU,QAAQ,cAAa;AAIlD,SAASC,oBAAoB,QAAQ,sCAAqC;AAC1E,SAASC,eAAe,QAAQ,qCAAoC;AACpE,SAASC,uBAAuB,QAAQ,kCAAiC;AAEzE,OAAO,MAAMC,wBAAwC,OAAOC;IAC1D,MAAM,EAAEC,CAAC,EAAE,GAAGD;IAEd,MAAME,aAAaN,qBAAqBI;IAExC,MAAMG,WAAWD,WAAWE,MAAM,CAACC,IAAI,EAAEC,oBACrC;QACEC,OAAO,OAAOP,IAAIQ,IAAI,EAAED,UAAU,WAAWP,IAAIQ,IAAI,CAACD,KAAK,GAAG;QAC9DE,UAAU,OAAOT,IAAIQ,IAAI,EAAEC,aAAa,WAAWT,IAAIQ,IAAI,CAACC,QAAQ,GAAG;IACzE,IACA;QACEF,OAAO,OAAOP,IAAIQ,IAAI,EAAED,UAAU,WAAWP,IAAIQ,IAAI,CAACD,KAAK,GAAG;IAChE;IAEJ,MAAMT,wBAAwB;QAC5BI;QACAM,MAAML;QACNH;IACF;IAEA,OAAOU,SAASC,IAAI,CAClB;QACEC,SAASX,EAAE;IACb,GACA;QACEY,SAAShB,gBAAgB;YACvBgB,SAAS,IAAIC;YACbd;QACF;QACAN,QAAQC,WAAWoB,EAAE;IACvB;AAEJ,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractJWT.d.ts","sourceRoot":"","sources":["../../src/auth/extractJWT.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"extractJWT.d.ts","sourceRoot":"","sources":["../../src/auth/extractJWT.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AA+D1D,eAAO,MAAM,UAAU,SAAU,IAAI,CAAC,wBAAwB,EAAE,cAAc,CAAC,KAAG,IAAI,GAAG,MAcxF,CAAA"}
|
package/dist/auth/extractJWT.js
CHANGED
|
@@ -2,24 +2,38 @@ import { parseCookies } from '../utilities/parseCookies.js';
|
|
|
2
2
|
const extractionMethods = {
|
|
3
3
|
Bearer: ({ headers })=>{
|
|
4
4
|
const jwtFromHeader = headers.get('Authorization');
|
|
5
|
-
//
|
|
6
|
-
// in addition to the payload default JWT format
|
|
5
|
+
// RFC6750 OAuth 2.0 Bearer token
|
|
7
6
|
if (jwtFromHeader?.startsWith('Bearer ')) {
|
|
8
7
|
return jwtFromHeader.replace('Bearer ', '');
|
|
9
8
|
}
|
|
10
9
|
return null;
|
|
11
10
|
},
|
|
12
11
|
cookie: ({ headers, payload })=>{
|
|
13
|
-
const origin = headers.get('Origin');
|
|
14
12
|
const cookies = parseCookies(headers);
|
|
15
13
|
const tokenCookieName = `${payload.config.cookiePrefix}-token`;
|
|
16
14
|
const cookieToken = cookies.get(tokenCookieName);
|
|
17
15
|
if (!cookieToken) {
|
|
18
16
|
return null;
|
|
19
17
|
}
|
|
20
|
-
|
|
18
|
+
const origin = headers.get('Origin');
|
|
19
|
+
// Origin present — validate against csrf allowlist
|
|
20
|
+
if (origin) {
|
|
21
|
+
if (payload.config.csrf.length === 0 || payload.config.csrf.includes(origin)) {
|
|
22
|
+
return cookieToken;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
// No Origin and no csrf configured — no allowlist to enforce
|
|
27
|
+
if (payload.config.csrf.length === 0) {
|
|
28
|
+
return cookieToken;
|
|
29
|
+
}
|
|
30
|
+
// No Origin with csrf configured — fall back to Sec-Fetch-Site
|
|
31
|
+
const secFetchSite = headers.get('Sec-Fetch-Site');
|
|
32
|
+
// Allow same-origin, same-site, and direct navigations (none)
|
|
33
|
+
if (secFetchSite === 'same-origin' || secFetchSite === 'same-site' || secFetchSite === 'none') {
|
|
21
34
|
return cookieToken;
|
|
22
35
|
}
|
|
36
|
+
// Reject cross-site requests and missing header (non-browser clients)
|
|
23
37
|
return null;
|
|
24
38
|
},
|
|
25
39
|
JWT: ({ headers })=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/auth/extractJWT.ts"],"sourcesContent":["import type { BasePayload } from '../index.js'\nimport type { AuthStrategyFunctionArgs } from './index.js'\n\nimport { parseCookies } from '../utilities/parseCookies.js'\n\ntype ExtractionMethod = (args: { headers: Headers; payload: BasePayload }) => null | string\n\nconst extractionMethods: Record<string, ExtractionMethod> = {\n Bearer: ({ headers }) => {\n const jwtFromHeader = headers.get('Authorization')\n\n //
|
|
1
|
+
{"version":3,"sources":["../../src/auth/extractJWT.ts"],"sourcesContent":["import type { BasePayload } from '../index.js'\nimport type { AuthStrategyFunctionArgs } from './index.js'\n\nimport { parseCookies } from '../utilities/parseCookies.js'\n\ntype ExtractionMethod = (args: { headers: Headers; payload: BasePayload }) => null | string\n\nconst extractionMethods: Record<string, ExtractionMethod> = {\n Bearer: ({ headers }) => {\n const jwtFromHeader = headers.get('Authorization')\n\n // RFC6750 OAuth 2.0 Bearer token\n if (jwtFromHeader?.startsWith('Bearer ')) {\n return jwtFromHeader.replace('Bearer ', '')\n }\n\n return null\n },\n cookie: ({ headers, payload }) => {\n const cookies = parseCookies(headers)\n const tokenCookieName = `${payload.config.cookiePrefix}-token`\n const cookieToken = cookies.get(tokenCookieName)\n\n if (!cookieToken) {\n return null\n }\n\n const origin = headers.get('Origin')\n\n // Origin present — validate against csrf allowlist\n if (origin) {\n if (payload.config.csrf.length === 0 || payload.config.csrf.includes(origin)) {\n return cookieToken\n }\n return null\n }\n\n // No Origin and no csrf configured — no allowlist to enforce\n if (payload.config.csrf.length === 0) {\n return cookieToken\n }\n\n // No Origin with csrf configured — fall back to Sec-Fetch-Site\n const secFetchSite = headers.get('Sec-Fetch-Site')\n\n // Allow same-origin, same-site, and direct navigations (none)\n if (secFetchSite === 'same-origin' || secFetchSite === 'same-site' || secFetchSite === 'none') {\n return cookieToken\n }\n\n // Reject cross-site requests and missing header (non-browser clients)\n return null\n },\n JWT: ({ headers }) => {\n const jwtFromHeader = headers.get('Authorization')\n\n if (jwtFromHeader?.startsWith('JWT ')) {\n return jwtFromHeader.replace('JWT ', '')\n }\n\n return null\n },\n}\n\nexport const extractJWT = (args: Omit<AuthStrategyFunctionArgs, 'strategyName'>): null | string => {\n const { headers, payload } = args\n\n const extractionOrder = payload.config.auth.jwtOrder\n\n for (const extractionStrategy of extractionOrder) {\n const result = extractionMethods[extractionStrategy]!({ headers, payload })\n\n if (result) {\n return result\n }\n }\n\n return null\n}\n"],"names":["parseCookies","extractionMethods","Bearer","headers","jwtFromHeader","get","startsWith","replace","cookie","payload","cookies","tokenCookieName","config","cookiePrefix","cookieToken","origin","csrf","length","includes","secFetchSite","JWT","extractJWT","args","extractionOrder","auth","jwtOrder","extractionStrategy","result"],"mappings":"AAGA,SAASA,YAAY,QAAQ,+BAA8B;AAI3D,MAAMC,oBAAsD;IAC1DC,QAAQ,CAAC,EAAEC,OAAO,EAAE;QAClB,MAAMC,gBAAgBD,QAAQE,GAAG,CAAC;QAElC,iCAAiC;QACjC,IAAID,eAAeE,WAAW,YAAY;YACxC,OAAOF,cAAcG,OAAO,CAAC,WAAW;QAC1C;QAEA,OAAO;IACT;IACAC,QAAQ,CAAC,EAAEL,OAAO,EAAEM,OAAO,EAAE;QAC3B,MAAMC,UAAUV,aAAaG;QAC7B,MAAMQ,kBAAkB,GAAGF,QAAQG,MAAM,CAACC,YAAY,CAAC,MAAM,CAAC;QAC9D,MAAMC,cAAcJ,QAAQL,GAAG,CAACM;QAEhC,IAAI,CAACG,aAAa;YAChB,OAAO;QACT;QAEA,MAAMC,SAASZ,QAAQE,GAAG,CAAC;QAE3B,mDAAmD;QACnD,IAAIU,QAAQ;YACV,IAAIN,QAAQG,MAAM,CAACI,IAAI,CAACC,MAAM,KAAK,KAAKR,QAAQG,MAAM,CAACI,IAAI,CAACE,QAAQ,CAACH,SAAS;gBAC5E,OAAOD;YACT;YACA,OAAO;QACT;QAEA,6DAA6D;QAC7D,IAAIL,QAAQG,MAAM,CAACI,IAAI,CAACC,MAAM,KAAK,GAAG;YACpC,OAAOH;QACT;QAEA,+DAA+D;QAC/D,MAAMK,eAAehB,QAAQE,GAAG,CAAC;QAEjC,8DAA8D;QAC9D,IAAIc,iBAAiB,iBAAiBA,iBAAiB,eAAeA,iBAAiB,QAAQ;YAC7F,OAAOL;QACT;QAEA,sEAAsE;QACtE,OAAO;IACT;IACAM,KAAK,CAAC,EAAEjB,OAAO,EAAE;QACf,MAAMC,gBAAgBD,QAAQE,GAAG,CAAC;QAElC,IAAID,eAAeE,WAAW,SAAS;YACrC,OAAOF,cAAcG,OAAO,CAAC,QAAQ;QACvC;QAEA,OAAO;IACT;AACF;AAEA,OAAO,MAAMc,aAAa,CAACC;IACzB,MAAM,EAAEnB,OAAO,EAAEM,OAAO,EAAE,GAAGa;IAE7B,MAAMC,kBAAkBd,QAAQG,MAAM,CAACY,IAAI,CAACC,QAAQ;IAEpD,KAAK,MAAMC,sBAAsBH,gBAAiB;QAChD,MAAMI,SAAS1B,iBAAiB,CAACyB,mBAAmB,CAAE;YAAEvB;YAASM;QAAQ;QAEzE,IAAIkB,QAAQ;YACV,OAAOA;QACT;IACF;IAEA,OAAO;AACT,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forgotPassword.d.ts","sourceRoot":"","sources":["../../../src/auth/operations/forgotPassword.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"forgotPassword.d.ts","sourceRoot":"","sources":["../../../src/auth/operations/forgotPassword.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,gCAAgC,EAChC,UAAU,EACX,MAAM,mCAAmC,CAAA;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACxD,OAAO,KAAK,EAAE,cAAc,EAAS,MAAM,sBAAsB,CAAA;AAcjE,MAAM,MAAM,SAAS,CAAC,KAAK,SAAS,kBAAkB,IAAI;IACxD,UAAU,EAAE,UAAU,CAAA;IACtB,IAAI,EAAE;QACJ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KACvB,GAAG,gCAAgC,CAAC,KAAK,CAAC,CAAC,gBAAgB,CAAC,CAAA;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,GAAG,EAAE,cAAc,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,MAAM,GAAG,MAAM,CAAA;AAE3B,eAAO,MAAM,uBAAuB,GAAU,KAAK,SAAS,kBAAkB,gBAC9D,SAAS,CAAC,KAAK,CAAC,KAC7B,OAAO,CAAC,IAAI,GAAG,MAAM,CA2LvB,CAAA"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import crypto from 'crypto';
|
|
2
2
|
import { status as httpStatus } from 'http-status';
|
|
3
|
-
import { URL } from 'url';
|
|
4
3
|
import { buildAfterOperation } from '../../collections/operations/utilities/buildAfterOperation.js';
|
|
5
4
|
import { buildBeforeOperation } from '../../collections/operations/utilities/buildBeforeOperation.js';
|
|
6
5
|
import { APIError } from '../../errors/index.js';
|
|
@@ -8,6 +7,7 @@ import { Forbidden } from '../../index.js';
|
|
|
8
7
|
import { appendNonTrashedFilter } from '../../utilities/appendNonTrashedFilter.js';
|
|
9
8
|
import { commitTransaction } from '../../utilities/commitTransaction.js';
|
|
10
9
|
import { formatAdminURL } from '../../utilities/formatAdminURL.js';
|
|
10
|
+
import { getRequestOrigin } from '../../utilities/getRequestOrigin.js';
|
|
11
11
|
import { initTransaction } from '../../utilities/initTransaction.js';
|
|
12
12
|
import { killTransaction } from '../../utilities/killTransaction.js';
|
|
13
13
|
import { getLoginOptions } from '../getLoginOptions.js';
|
|
@@ -86,9 +86,10 @@ export const forgotPasswordOperation = async (incomingArgs)=>{
|
|
|
86
86
|
req
|
|
87
87
|
});
|
|
88
88
|
if (!disableEmail && user.email) {
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
const serverURL = getRequestOrigin({
|
|
90
|
+
config,
|
|
91
|
+
req
|
|
92
|
+
});
|
|
92
93
|
const forgotURL = formatAdminURL({
|
|
93
94
|
adminRoute: config.routes.admin,
|
|
94
95
|
path: `${config.admin.routes.reset}/${token}`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/auth/operations/forgotPassword.ts"],"sourcesContent":["import crypto from 'crypto'\nimport { status as httpStatus } from 'http-status'\nimport { URL } from 'url'\n\nimport type {\n AuthOperationsFromCollectionSlug,\n Collection,\n} from '../../collections/config/types.js'\nimport type { AuthCollectionSlug } from '../../index.js'\nimport type { PayloadRequest, Where } from '../../types/index.js'\n\nimport { buildAfterOperation } from '../../collections/operations/utilities/buildAfterOperation.js'\nimport { buildBeforeOperation } from '../../collections/operations/utilities/buildBeforeOperation.js'\nimport { APIError } from '../../errors/index.js'\nimport { Forbidden } from '../../index.js'\nimport { appendNonTrashedFilter } from '../../utilities/appendNonTrashedFilter.js'\nimport { commitTransaction } from '../../utilities/commitTransaction.js'\nimport { formatAdminURL } from '../../utilities/formatAdminURL.js'\nimport { initTransaction } from '../../utilities/initTransaction.js'\nimport { killTransaction } from '../../utilities/killTransaction.js'\nimport { getLoginOptions } from '../getLoginOptions.js'\n\nexport type Arguments<TSlug extends AuthCollectionSlug> = {\n collection: Collection\n data: {\n [key: string]: unknown\n } & AuthOperationsFromCollectionSlug<TSlug>['forgotPassword']\n disableEmail?: boolean\n expiration?: number\n overrideAccess?: boolean\n req: PayloadRequest\n}\n\nexport type Result = string\n\nexport const forgotPasswordOperation = async <TSlug extends AuthCollectionSlug>(\n incomingArgs: Arguments<TSlug>,\n): Promise<null | string> => {\n const loginWithUsername = incomingArgs.collection.config.auth.loginWithUsername\n const { data, overrideAccess } = incomingArgs\n\n const { canLoginWithEmail, canLoginWithUsername } = getLoginOptions(loginWithUsername)\n\n const sanitizedEmail =\n (canLoginWithEmail && (incomingArgs.data.email || '').toLowerCase().trim()) || null\n const sanitizedUsername =\n 'username' in data && typeof data?.username === 'string'\n ? data.username.toLowerCase().trim()\n : null\n\n let args = incomingArgs\n\n if (incomingArgs.collection.config.auth.disableLocalStrategy) {\n throw new Forbidden(incomingArgs.req.t)\n }\n if (!sanitizedEmail && !sanitizedUsername) {\n throw new APIError(\n `Missing ${loginWithUsername ? 'username' : 'email'}.`,\n httpStatus.BAD_REQUEST,\n )\n }\n\n try {\n const shouldCommit = await initTransaction(args.req)\n\n // /////////////////////////////////////\n // beforeOperation - Collection\n // /////////////////////////////////////\n args = await buildBeforeOperation({\n args,\n collection: args.collection.config,\n operation: 'forgotPassword',\n overrideAccess,\n })\n\n const {\n collection: { config: collectionConfig },\n disableEmail,\n expiration,\n req: {\n payload: { config, email },\n payload,\n },\n req,\n } = args\n\n // /////////////////////////////////////\n // Forget password\n // /////////////////////////////////////\n\n let token: string = crypto.randomBytes(20).toString('hex')\n type UserDoc = {\n email?: string\n id: number | string\n resetPasswordExpiration?: string\n resetPasswordToken?: string\n }\n\n if (!sanitizedEmail && !sanitizedUsername) {\n throw new APIError(\n `Missing ${loginWithUsername ? 'username' : 'email'}.`,\n httpStatus.BAD_REQUEST,\n )\n }\n\n let whereConstraint: Where = {}\n\n if (canLoginWithEmail && sanitizedEmail) {\n whereConstraint = {\n email: {\n equals: sanitizedEmail,\n },\n }\n } else if (canLoginWithUsername && sanitizedUsername) {\n whereConstraint = {\n username: {\n equals: sanitizedUsername,\n },\n }\n }\n\n // Exclude trashed users unless `trash: true`\n whereConstraint = appendNonTrashedFilter({\n enableTrash: collectionConfig.trash,\n trash: false,\n where: whereConstraint,\n })\n\n let user = await payload.db.findOne<UserDoc>({\n collection: collectionConfig.slug,\n req,\n where: whereConstraint,\n })\n\n // We don't want to indicate specifically that an email was not found,\n // as doing so could lead to the exposure of registered emails.\n // Therefore, we prefer to fail silently.\n if (!user) {\n await commitTransaction(args.req)\n return null\n }\n\n const resetPasswordExpiration = new Date(\n Date.now() + (collectionConfig.auth?.forgotPassword?.expiration ?? expiration ?? 3600000),\n ).toISOString()\n\n user = await payload.update({\n id: user.id,\n collection: collectionConfig.slug,\n data: {\n resetPasswordExpiration,\n resetPasswordToken: token,\n },\n req,\n })\n\n if (!disableEmail && user.email) {\n const protocol = new URL(req.url!).protocol // includes the final :\n const serverURL =\n config.serverURL !== null && config.serverURL !== ''\n ? config.serverURL\n : `${protocol}//${req.headers.get('host')}`\n const forgotURL = formatAdminURL({\n adminRoute: config.routes.admin,\n path: `${config.admin.routes.reset}/${token}`,\n serverURL,\n })\n let html = `${req.t('authentication:youAreReceivingResetPassword')}\n <a href=\"${forgotURL}\">${forgotURL}</a>\n ${req.t('authentication:youDidNotRequestPassword')}`\n\n if (typeof collectionConfig.auth.forgotPassword?.generateEmailHTML === 'function') {\n html = await collectionConfig.auth.forgotPassword.generateEmailHTML({\n req,\n token,\n user,\n })\n }\n\n let subject = req.t('authentication:resetYourPassword')\n\n if (typeof collectionConfig.auth.forgotPassword?.generateEmailSubject === 'function') {\n subject = await collectionConfig.auth.forgotPassword.generateEmailSubject({\n req,\n token,\n user,\n })\n }\n\n await email.sendEmail({\n from: `\"${email.defaultFromName}\" <${email.defaultFromAddress}>`,\n html,\n subject,\n to: user.email,\n })\n }\n\n // /////////////////////////////////////\n // afterForgotPassword - Collection\n // /////////////////////////////////////\n\n if (collectionConfig.hooks?.afterForgotPassword?.length) {\n for (const hook of collectionConfig.hooks.afterForgotPassword) {\n await hook({ args, collection: args.collection?.config, context: req.context })\n }\n }\n\n // /////////////////////////////////////\n // afterOperation - Collection\n // /////////////////////////////////////\n\n token = await buildAfterOperation({\n args,\n collection: args.collection?.config,\n operation: 'forgotPassword',\n overrideAccess,\n result: token,\n })\n\n if (shouldCommit) {\n await commitTransaction(req)\n }\n\n return token\n } catch (error: unknown) {\n await killTransaction(args.req)\n throw error\n }\n}\n"],"names":["crypto","status","httpStatus","URL","buildAfterOperation","buildBeforeOperation","APIError","Forbidden","appendNonTrashedFilter","commitTransaction","formatAdminURL","initTransaction","killTransaction","getLoginOptions","forgotPasswordOperation","incomingArgs","loginWithUsername","collection","config","auth","data","overrideAccess","canLoginWithEmail","canLoginWithUsername","sanitizedEmail","email","toLowerCase","trim","sanitizedUsername","username","args","disableLocalStrategy","req","t","BAD_REQUEST","shouldCommit","operation","collectionConfig","disableEmail","expiration","payload","token","randomBytes","toString","whereConstraint","equals","enableTrash","trash","where","user","db","findOne","slug","resetPasswordExpiration","Date","now","forgotPassword","toISOString","update","id","resetPasswordToken","protocol","url","serverURL","headers","get","forgotURL","adminRoute","routes","admin","path","reset","html","generateEmailHTML","subject","generateEmailSubject","sendEmail","from","defaultFromName","defaultFromAddress","to","hooks","afterForgotPassword","length","hook","context","result","error"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/auth/operations/forgotPassword.ts"],"sourcesContent":["import crypto from 'crypto'\nimport { status as httpStatus } from 'http-status'\n\nimport type {\n AuthOperationsFromCollectionSlug,\n Collection,\n} from '../../collections/config/types.js'\nimport type { AuthCollectionSlug } from '../../index.js'\nimport type { PayloadRequest, Where } from '../../types/index.js'\n\nimport { buildAfterOperation } from '../../collections/operations/utilities/buildAfterOperation.js'\nimport { buildBeforeOperation } from '../../collections/operations/utilities/buildBeforeOperation.js'\nimport { APIError } from '../../errors/index.js'\nimport { Forbidden } from '../../index.js'\nimport { appendNonTrashedFilter } from '../../utilities/appendNonTrashedFilter.js'\nimport { commitTransaction } from '../../utilities/commitTransaction.js'\nimport { formatAdminURL } from '../../utilities/formatAdminURL.js'\nimport { getRequestOrigin } from '../../utilities/getRequestOrigin.js'\nimport { initTransaction } from '../../utilities/initTransaction.js'\nimport { killTransaction } from '../../utilities/killTransaction.js'\nimport { getLoginOptions } from '../getLoginOptions.js'\n\nexport type Arguments<TSlug extends AuthCollectionSlug> = {\n collection: Collection\n data: {\n [key: string]: unknown\n } & AuthOperationsFromCollectionSlug<TSlug>['forgotPassword']\n disableEmail?: boolean\n expiration?: number\n overrideAccess?: boolean\n req: PayloadRequest\n}\n\nexport type Result = string\n\nexport const forgotPasswordOperation = async <TSlug extends AuthCollectionSlug>(\n incomingArgs: Arguments<TSlug>,\n): Promise<null | string> => {\n const loginWithUsername = incomingArgs.collection.config.auth.loginWithUsername\n const { data, overrideAccess } = incomingArgs\n\n const { canLoginWithEmail, canLoginWithUsername } = getLoginOptions(loginWithUsername)\n\n const sanitizedEmail =\n (canLoginWithEmail && (incomingArgs.data.email || '').toLowerCase().trim()) || null\n const sanitizedUsername =\n 'username' in data && typeof data?.username === 'string'\n ? data.username.toLowerCase().trim()\n : null\n\n let args = incomingArgs\n\n if (incomingArgs.collection.config.auth.disableLocalStrategy) {\n throw new Forbidden(incomingArgs.req.t)\n }\n if (!sanitizedEmail && !sanitizedUsername) {\n throw new APIError(\n `Missing ${loginWithUsername ? 'username' : 'email'}.`,\n httpStatus.BAD_REQUEST,\n )\n }\n\n try {\n const shouldCommit = await initTransaction(args.req)\n\n // /////////////////////////////////////\n // beforeOperation - Collection\n // /////////////////////////////////////\n args = await buildBeforeOperation({\n args,\n collection: args.collection.config,\n operation: 'forgotPassword',\n overrideAccess,\n })\n\n const {\n collection: { config: collectionConfig },\n disableEmail,\n expiration,\n req: {\n payload: { config, email },\n payload,\n },\n req,\n } = args\n\n // /////////////////////////////////////\n // Forget password\n // /////////////////////////////////////\n\n let token: string = crypto.randomBytes(20).toString('hex')\n type UserDoc = {\n email?: string\n id: number | string\n resetPasswordExpiration?: string\n resetPasswordToken?: string\n }\n\n if (!sanitizedEmail && !sanitizedUsername) {\n throw new APIError(\n `Missing ${loginWithUsername ? 'username' : 'email'}.`,\n httpStatus.BAD_REQUEST,\n )\n }\n\n let whereConstraint: Where = {}\n\n if (canLoginWithEmail && sanitizedEmail) {\n whereConstraint = {\n email: {\n equals: sanitizedEmail,\n },\n }\n } else if (canLoginWithUsername && sanitizedUsername) {\n whereConstraint = {\n username: {\n equals: sanitizedUsername,\n },\n }\n }\n\n // Exclude trashed users unless `trash: true`\n whereConstraint = appendNonTrashedFilter({\n enableTrash: collectionConfig.trash,\n trash: false,\n where: whereConstraint,\n })\n\n let user = await payload.db.findOne<UserDoc>({\n collection: collectionConfig.slug,\n req,\n where: whereConstraint,\n })\n\n // We don't want to indicate specifically that an email was not found,\n // as doing so could lead to the exposure of registered emails.\n // Therefore, we prefer to fail silently.\n if (!user) {\n await commitTransaction(args.req)\n return null\n }\n\n const resetPasswordExpiration = new Date(\n Date.now() + (collectionConfig.auth?.forgotPassword?.expiration ?? expiration ?? 3600000),\n ).toISOString()\n\n user = await payload.update({\n id: user.id,\n collection: collectionConfig.slug,\n data: {\n resetPasswordExpiration,\n resetPasswordToken: token,\n },\n req,\n })\n\n if (!disableEmail && user.email) {\n const serverURL = getRequestOrigin({ config, req })\n const forgotURL = formatAdminURL({\n adminRoute: config.routes.admin,\n path: `${config.admin.routes.reset}/${token}`,\n serverURL,\n })\n let html = `${req.t('authentication:youAreReceivingResetPassword')}\n <a href=\"${forgotURL}\">${forgotURL}</a>\n ${req.t('authentication:youDidNotRequestPassword')}`\n\n if (typeof collectionConfig.auth.forgotPassword?.generateEmailHTML === 'function') {\n html = await collectionConfig.auth.forgotPassword.generateEmailHTML({\n req,\n token,\n user,\n })\n }\n\n let subject = req.t('authentication:resetYourPassword')\n\n if (typeof collectionConfig.auth.forgotPassword?.generateEmailSubject === 'function') {\n subject = await collectionConfig.auth.forgotPassword.generateEmailSubject({\n req,\n token,\n user,\n })\n }\n\n await email.sendEmail({\n from: `\"${email.defaultFromName}\" <${email.defaultFromAddress}>`,\n html,\n subject,\n to: user.email,\n })\n }\n\n // /////////////////////////////////////\n // afterForgotPassword - Collection\n // /////////////////////////////////////\n\n if (collectionConfig.hooks?.afterForgotPassword?.length) {\n for (const hook of collectionConfig.hooks.afterForgotPassword) {\n await hook({ args, collection: args.collection?.config, context: req.context })\n }\n }\n\n // /////////////////////////////////////\n // afterOperation - Collection\n // /////////////////////////////////////\n\n token = await buildAfterOperation({\n args,\n collection: args.collection?.config,\n operation: 'forgotPassword',\n overrideAccess,\n result: token,\n })\n\n if (shouldCommit) {\n await commitTransaction(req)\n }\n\n return token\n } catch (error: unknown) {\n await killTransaction(args.req)\n throw error\n }\n}\n"],"names":["crypto","status","httpStatus","buildAfterOperation","buildBeforeOperation","APIError","Forbidden","appendNonTrashedFilter","commitTransaction","formatAdminURL","getRequestOrigin","initTransaction","killTransaction","getLoginOptions","forgotPasswordOperation","incomingArgs","loginWithUsername","collection","config","auth","data","overrideAccess","canLoginWithEmail","canLoginWithUsername","sanitizedEmail","email","toLowerCase","trim","sanitizedUsername","username","args","disableLocalStrategy","req","t","BAD_REQUEST","shouldCommit","operation","collectionConfig","disableEmail","expiration","payload","token","randomBytes","toString","whereConstraint","equals","enableTrash","trash","where","user","db","findOne","slug","resetPasswordExpiration","Date","now","forgotPassword","toISOString","update","id","resetPasswordToken","serverURL","forgotURL","adminRoute","routes","admin","path","reset","html","generateEmailHTML","subject","generateEmailSubject","sendEmail","from","defaultFromName","defaultFromAddress","to","hooks","afterForgotPassword","length","hook","context","result","error"],"mappings":"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"}
|
|
@@ -5,6 +5,11 @@ export const meOperation = async (args)=>{
|
|
|
5
5
|
user: null
|
|
6
6
|
};
|
|
7
7
|
if (req.user) {
|
|
8
|
+
if (req.user.collection !== collection.config.slug) {
|
|
9
|
+
return {
|
|
10
|
+
user: null
|
|
11
|
+
};
|
|
12
|
+
}
|
|
8
13
|
const { pathname } = req;
|
|
9
14
|
const isGraphQL = pathname === `/api${req.payload.config.routes.graphQL}`;
|
|
10
15
|
const user = await req.payload.findByID({
|
|
@@ -23,11 +28,6 @@ export const meOperation = async (args)=>{
|
|
|
23
28
|
user.collection = collection.config.slug;
|
|
24
29
|
user._strategy = req.user._strategy;
|
|
25
30
|
}
|
|
26
|
-
if (req.user.collection !== collection.config.slug) {
|
|
27
|
-
return {
|
|
28
|
-
user: null
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
31
|
// /////////////////////////////////////
|
|
32
32
|
// me hook - Collection
|
|
33
33
|
// /////////////////////////////////////
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/auth/operations/me.ts"],"sourcesContent":["import { decodeJwt } from 'jose'\n\nimport type { Collection } from '../../collections/config/types.js'\nimport type { TypedUser } from '../../index.js'\nimport type { JoinQuery, PayloadRequest, PopulateType, SelectType } from '../../types/index.js'\nimport type { ClientUser } from '../types.js'\n\nexport type MeOperationResult = {\n collection?: string\n exp?: number\n /** @deprecated\n * use:\n * ```ts\n * user._strategy\n * ```\n */\n strategy?: string\n token?: string\n user?: ClientUser\n}\n\nexport type Arguments = {\n collection: Collection\n currentToken?: string\n depth?: number\n draft?: boolean\n joins?: JoinQuery\n populate?: PopulateType\n req: PayloadRequest\n select?: SelectType\n}\n\nexport const meOperation = async (args: Arguments): Promise<MeOperationResult> => {\n const { collection, currentToken, depth, draft, joins, populate, req, select } = args\n\n let result: MeOperationResult = {\n user: null!,\n }\n\n if (req.user) {\n const { pathname } = req\n const isGraphQL = pathname === `/api${req.payload.config.routes.graphQL}`\n\n const user = (await req.payload.findByID({\n id: req.user.id,\n collection: collection.config.slug,\n depth: isGraphQL ? 0 : (depth ?? collection.config.auth.depth),\n draft,\n joins,\n overrideAccess: false,\n populate,\n req,\n select,\n showHiddenFields: false,\n })) as TypedUser\n\n if (user) {\n user.collection = collection.config.slug\n user._strategy = req.user._strategy\n }\n\n
|
|
1
|
+
{"version":3,"sources":["../../../src/auth/operations/me.ts"],"sourcesContent":["import { decodeJwt } from 'jose'\n\nimport type { Collection } from '../../collections/config/types.js'\nimport type { TypedUser } from '../../index.js'\nimport type { JoinQuery, PayloadRequest, PopulateType, SelectType } from '../../types/index.js'\nimport type { ClientUser } from '../types.js'\n\nexport type MeOperationResult = {\n collection?: string\n exp?: number\n /** @deprecated\n * use:\n * ```ts\n * user._strategy\n * ```\n */\n strategy?: string\n token?: string\n user?: ClientUser\n}\n\nexport type Arguments = {\n collection: Collection\n currentToken?: string\n depth?: number\n draft?: boolean\n joins?: JoinQuery\n populate?: PopulateType\n req: PayloadRequest\n select?: SelectType\n}\n\nexport const meOperation = async (args: Arguments): Promise<MeOperationResult> => {\n const { collection, currentToken, depth, draft, joins, populate, req, select } = args\n\n let result: MeOperationResult = {\n user: null!,\n }\n\n if (req.user) {\n if (req.user.collection !== collection.config.slug) {\n return {\n user: null!,\n }\n }\n\n const { pathname } = req\n const isGraphQL = pathname === `/api${req.payload.config.routes.graphQL}`\n\n const user = (await req.payload.findByID({\n id: req.user.id,\n collection: collection.config.slug,\n depth: isGraphQL ? 0 : (depth ?? collection.config.auth.depth),\n draft,\n joins,\n overrideAccess: false,\n populate,\n req,\n select,\n showHiddenFields: false,\n })) as TypedUser\n\n if (user) {\n user.collection = collection.config.slug\n user._strategy = req.user._strategy\n }\n\n // /////////////////////////////////////\n // me hook - Collection\n // /////////////////////////////////////\n\n for (const meHook of collection.config.hooks.me) {\n const hookResult = await meHook({ args, user })\n\n if (hookResult) {\n result.user = hookResult.user\n result.exp = hookResult.exp\n\n break\n }\n }\n\n result.collection = req.user.collection\n /** @deprecated\n * use:\n * ```ts\n * user._strategy\n * ```\n */\n result.strategy = req.user._strategy\n\n if (!result.user) {\n result.user = user\n\n if (currentToken) {\n const decoded = decodeJwt(currentToken)\n if (decoded) {\n result.exp = decoded.exp\n }\n if (!collection.config.auth.removeTokenFromResponses) {\n result.token = currentToken\n }\n }\n }\n }\n\n // /////////////////////////////////////\n // After Me - Collection\n // /////////////////////////////////////\n\n if (collection.config.hooks?.afterMe?.length) {\n for (const hook of collection.config.hooks.afterMe) {\n result =\n (await hook({\n collection: collection?.config,\n context: req.context,\n req,\n response: result,\n })) || result\n }\n }\n\n return result\n}\n"],"names":["decodeJwt","meOperation","args","collection","currentToken","depth","draft","joins","populate","req","select","result","user","config","slug","pathname","isGraphQL","payload","routes","graphQL","findByID","id","auth","overrideAccess","showHiddenFields","_strategy","meHook","hooks","me","hookResult","exp","strategy","decoded","removeTokenFromResponses","token","afterMe","length","hook","context","response"],"mappings":"AAAA,SAASA,SAAS,QAAQ,OAAM;AAgChC,OAAO,MAAMC,cAAc,OAAOC;IAChC,MAAM,EAAEC,UAAU,EAAEC,YAAY,EAAEC,KAAK,EAAEC,KAAK,EAAEC,KAAK,EAAEC,QAAQ,EAAEC,GAAG,EAAEC,MAAM,EAAE,GAAGR;IAEjF,IAAIS,SAA4B;QAC9BC,MAAM;IACR;IAEA,IAAIH,IAAIG,IAAI,EAAE;QACZ,IAAIH,IAAIG,IAAI,CAACT,UAAU,KAAKA,WAAWU,MAAM,CAACC,IAAI,EAAE;YAClD,OAAO;gBACLF,MAAM;YACR;QACF;QAEA,MAAM,EAAEG,QAAQ,EAAE,GAAGN;QACrB,MAAMO,YAAYD,aAAa,CAAC,IAAI,EAAEN,IAAIQ,OAAO,CAACJ,MAAM,CAACK,MAAM,CAACC,OAAO,EAAE;QAEzE,MAAMP,OAAQ,MAAMH,IAAIQ,OAAO,CAACG,QAAQ,CAAC;YACvCC,IAAIZ,IAAIG,IAAI,CAACS,EAAE;YACflB,YAAYA,WAAWU,MAAM,CAACC,IAAI;YAClCT,OAAOW,YAAY,IAAKX,SAASF,WAAWU,MAAM,CAACS,IAAI,CAACjB,KAAK;YAC7DC;YACAC;YACAgB,gBAAgB;YAChBf;YACAC;YACAC;YACAc,kBAAkB;QACpB;QAEA,IAAIZ,MAAM;YACRA,KAAKT,UAAU,GAAGA,WAAWU,MAAM,CAACC,IAAI;YACxCF,KAAKa,SAAS,GAAGhB,IAAIG,IAAI,CAACa,SAAS;QACrC;QAEA,wCAAwC;QACxC,uBAAuB;QACvB,wCAAwC;QAExC,KAAK,MAAMC,UAAUvB,WAAWU,MAAM,CAACc,KAAK,CAACC,EAAE,CAAE;YAC/C,MAAMC,aAAa,MAAMH,OAAO;gBAAExB;gBAAMU;YAAK;YAE7C,IAAIiB,YAAY;gBACdlB,OAAOC,IAAI,GAAGiB,WAAWjB,IAAI;gBAC7BD,OAAOmB,GAAG,GAAGD,WAAWC,GAAG;gBAE3B;YACF;QACF;QAEAnB,OAAOR,UAAU,GAAGM,IAAIG,IAAI,CAACT,UAAU;QACvC;;;;;KAKC,GACDQ,OAAOoB,QAAQ,GAAGtB,IAAIG,IAAI,CAACa,SAAS;QAEpC,IAAI,CAACd,OAAOC,IAAI,EAAE;YAChBD,OAAOC,IAAI,GAAGA;YAEd,IAAIR,cAAc;gBAChB,MAAM4B,UAAUhC,UAAUI;gBAC1B,IAAI4B,SAAS;oBACXrB,OAAOmB,GAAG,GAAGE,QAAQF,GAAG;gBAC1B;gBACA,IAAI,CAAC3B,WAAWU,MAAM,CAACS,IAAI,CAACW,wBAAwB,EAAE;oBACpDtB,OAAOuB,KAAK,GAAG9B;gBACjB;YACF;QACF;IACF;IAEA,wCAAwC;IACxC,wBAAwB;IACxB,wCAAwC;IAExC,IAAID,WAAWU,MAAM,CAACc,KAAK,EAAEQ,SAASC,QAAQ;QAC5C,KAAK,MAAMC,QAAQlC,WAAWU,MAAM,CAACc,KAAK,CAACQ,OAAO,CAAE;YAClDxB,SACE,AAAC,MAAM0B,KAAK;gBACVlC,YAAYA,YAAYU;gBACxByB,SAAS7B,IAAI6B,OAAO;gBACpB7B;gBACA8B,UAAU5B;YACZ,MAAOA;QACX;IACF;IAEA,OAAOA;AACT,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sendVerificationEmail.d.ts","sourceRoot":"","sources":["../../src/auth/sendVerificationEmail.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sendVerificationEmail.d.ts","sourceRoot":"","sources":["../../src/auth/sendVerificationEmail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAA;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAMvD,KAAK,IAAI,GAAG;IACV,UAAU,EAAE,UAAU,CAAA;IACtB,MAAM,EAAE,eAAe,CAAA;IACvB,YAAY,EAAE,OAAO,CAAA;IACrB,KAAK,EAAE,uBAAuB,CAAA;IAC9B,GAAG,EAAE,cAAc,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,SAAS,CAAA;CAChB,CAAA;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAuDrE"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { URL } from 'url';
|
|
2
1
|
import { formatAdminURL } from '../utilities/formatAdminURL.js';
|
|
2
|
+
import { getRequestOrigin } from '../utilities/getRequestOrigin.js';
|
|
3
3
|
export async function sendVerificationEmail(args) {
|
|
4
4
|
// Verify token from e-mail
|
|
5
5
|
const { collection: { config: collectionConfig }, config, disableEmail, email, req, token, user } = args;
|
|
6
6
|
if (!disableEmail) {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
const serverURL = getRequestOrigin({
|
|
8
|
+
config,
|
|
9
|
+
req
|
|
10
|
+
});
|
|
10
11
|
const verificationURL = formatAdminURL({
|
|
11
12
|
adminRoute: config.routes.admin,
|
|
12
13
|
path: `/${collectionConfig.slug}/verify/${token}`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/auth/sendVerificationEmail.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"sources":["../../src/auth/sendVerificationEmail.ts"],"sourcesContent":["import type { Collection } from '../collections/config/types.js'\nimport type { SanitizedConfig } from '../config/types.js'\nimport type { InitializedEmailAdapter } from '../email/types.js'\nimport type { TypedUser } from '../index.js'\nimport type { PayloadRequest } from '../types/index.js'\nimport type { VerifyConfig } from './types.js'\n\nimport { formatAdminURL } from '../utilities/formatAdminURL.js'\nimport { getRequestOrigin } from '../utilities/getRequestOrigin.js'\n\ntype Args = {\n collection: Collection\n config: SanitizedConfig\n disableEmail: boolean\n email: InitializedEmailAdapter\n req: PayloadRequest\n token: string\n user: TypedUser\n}\n\nexport async function sendVerificationEmail(args: Args): Promise<void> {\n // Verify token from e-mail\n const {\n collection: { config: collectionConfig },\n config,\n disableEmail,\n email,\n req,\n token,\n user,\n } = args\n\n if (!disableEmail) {\n const serverURL = getRequestOrigin({ config, req })\n\n const verificationURL = formatAdminURL({\n adminRoute: config.routes.admin,\n path: `/${collectionConfig.slug}/verify/${token}`,\n serverURL,\n })\n\n let html = `${req.t('authentication:newAccountCreated', {\n serverURL: config.serverURL,\n verificationURL,\n })}`\n\n const verify = collectionConfig.auth.verify as VerifyConfig\n\n // Allow config to override email content\n if (typeof verify.generateEmailHTML === 'function') {\n html = await verify.generateEmailHTML({\n req,\n token,\n user,\n })\n }\n\n let subject = req.t('authentication:verifyYourEmail')\n\n // Allow config to override email subject\n if (typeof verify.generateEmailSubject === 'function') {\n subject = await verify.generateEmailSubject({\n req,\n token,\n user,\n })\n }\n\n await email.sendEmail({\n from: `\"${email.defaultFromName}\" <${email.defaultFromAddress}>`,\n html,\n subject,\n to: user.email,\n })\n }\n}\n"],"names":["formatAdminURL","getRequestOrigin","sendVerificationEmail","args","collection","config","collectionConfig","disableEmail","email","req","token","user","serverURL","verificationURL","adminRoute","routes","admin","path","slug","html","t","verify","auth","generateEmailHTML","subject","generateEmailSubject","sendEmail","from","defaultFromName","defaultFromAddress","to"],"mappings":"AAOA,SAASA,cAAc,QAAQ,iCAAgC;AAC/D,SAASC,gBAAgB,QAAQ,mCAAkC;AAYnE,OAAO,eAAeC,sBAAsBC,IAAU;IACpD,2BAA2B;IAC3B,MAAM,EACJC,YAAY,EAAEC,QAAQC,gBAAgB,EAAE,EACxCD,MAAM,EACNE,YAAY,EACZC,KAAK,EACLC,GAAG,EACHC,KAAK,EACLC,IAAI,EACL,GAAGR;IAEJ,IAAI,CAACI,cAAc;QACjB,MAAMK,YAAYX,iBAAiB;YAAEI;YAAQI;QAAI;QAEjD,MAAMI,kBAAkBb,eAAe;YACrCc,YAAYT,OAAOU,MAAM,CAACC,KAAK;YAC/BC,MAAM,CAAC,CAAC,EAAEX,iBAAiBY,IAAI,CAAC,QAAQ,EAAER,OAAO;YACjDE;QACF;QAEA,IAAIO,OAAO,GAAGV,IAAIW,CAAC,CAAC,oCAAoC;YACtDR,WAAWP,OAAOO,SAAS;YAC3BC;QACF,IAAI;QAEJ,MAAMQ,SAASf,iBAAiBgB,IAAI,CAACD,MAAM;QAE3C,yCAAyC;QACzC,IAAI,OAAOA,OAAOE,iBAAiB,KAAK,YAAY;YAClDJ,OAAO,MAAME,OAAOE,iBAAiB,CAAC;gBACpCd;gBACAC;gBACAC;YACF;QACF;QAEA,IAAIa,UAAUf,IAAIW,CAAC,CAAC;QAEpB,yCAAyC;QACzC,IAAI,OAAOC,OAAOI,oBAAoB,KAAK,YAAY;YACrDD,UAAU,MAAMH,OAAOI,oBAAoB,CAAC;gBAC1ChB;gBACAC;gBACAC;YACF;QACF;QAEA,MAAMH,MAAMkB,SAAS,CAAC;YACpBC,MAAM,CAAC,CAAC,EAAEnB,MAAMoB,eAAe,CAAC,GAAG,EAAEpB,MAAMqB,kBAAkB,CAAC,CAAC,CAAC;YAChEV;YACAK;YACAM,IAAInB,KAAKH,KAAK;QAChB;IACF;AACF"}
|
|
@@ -9,7 +9,7 @@ import type { SanitizedConfig } from '../types.js';
|
|
|
9
9
|
* Also, if collection.defaultSort or joinField.defaultSort is not set, it will be set to the orderable field.
|
|
10
10
|
*/
|
|
11
11
|
export declare const setupOrderable: (config: SanitizedConfig) => void;
|
|
12
|
-
export declare const addOrderableFieldsAndHook: (collection: CollectionConfig, orderableFieldNames: string[]) => void;
|
|
12
|
+
export declare const addOrderableFieldsAndHook: (collection: CollectionConfig, orderableFieldNames: string[], joinFieldPathsByCollection?: Map<string, Map<string, string>>) => void;
|
|
13
13
|
/**
|
|
14
14
|
* The body of the reorder endpoint.
|
|
15
15
|
* @internal
|
|
@@ -24,5 +24,5 @@ export type OrderableEndpointBody = {
|
|
|
24
24
|
key: string;
|
|
25
25
|
};
|
|
26
26
|
};
|
|
27
|
-
export declare const addOrderableEndpoint: (config: SanitizedConfig) => void;
|
|
27
|
+
export declare const addOrderableEndpoint: (config: SanitizedConfig, joinFieldPathsByCollection: Map<string, Map<string, string>>) => void;
|
|
28
28
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/config/orderable/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAoB,gBAAgB,EAAE,MAAM,mCAAmC,CAAA;AAE3F,OAAO,KAAK,EAA4B,eAAe,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/config/orderable/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAoB,gBAAgB,EAAE,MAAM,mCAAmC,CAAA;AAE3F,OAAO,KAAK,EAA4B,eAAe,EAAE,MAAM,aAAa,CAAA;AAc5E;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,WAAY,eAAe,SA2DrD,CAAA;AAED,eAAO,MAAM,yBAAyB,eACxB,gBAAgB,uBACP,MAAM,EAAE,+BACA,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,SA2E9D,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,YAAY,EAAE,SAAS,GAAG,MAAM,CAAA;IAChC,kBAAkB,EAAE,MAAM,CAAA;IAC1B,MAAM,EAAE;QACN,EAAE,EAAE,MAAM,CAAA;QACV,GAAG,EAAE,MAAM,CAAA;KACZ,CAAA;CACF,CAAA;AAED,eAAO,MAAM,oBAAoB,WACvB,eAAe,8BACK,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,SA4L7D,CAAA"}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { status as httpStatus } from 'http-status';
|
|
2
2
|
import { executeAccess } from '../../auth/executeAccess.js';
|
|
3
3
|
import { APIError } from '../../errors/index.js';
|
|
4
|
+
import { combineWhereConstraints } from '../../utilities/combineWhereConstraints.js';
|
|
4
5
|
import { commitTransaction } from '../../utilities/commitTransaction.js';
|
|
5
6
|
import { initTransaction } from '../../utilities/initTransaction.js';
|
|
6
7
|
import { killTransaction } from '../../utilities/killTransaction.js';
|
|
7
8
|
import { traverseFields } from '../../utilities/traverseFields.js';
|
|
8
9
|
import { generateKeyBetween, generateNKeysBetween } from './fractional-indexing.js';
|
|
10
|
+
import { getJoinScopeContext } from './utils/getJoinScopeContext.js';
|
|
11
|
+
import { getJoinScopeWhereFromDocData } from './utils/getJoinScopeWhereFromDocData.js';
|
|
12
|
+
import { resolvePendingTargetKey } from './utils/resolvePendingTargetKey.js';
|
|
9
13
|
/**
|
|
10
14
|
* This function creates:
|
|
11
15
|
* - N fields per collection, named `_order` or `_<collection>_<joinField>_order`
|
|
@@ -15,6 +19,7 @@ import { generateKeyBetween, generateNKeysBetween } from './fractional-indexing.
|
|
|
15
19
|
* Also, if collection.defaultSort or joinField.defaultSort is not set, it will be set to the orderable field.
|
|
16
20
|
*/ export const setupOrderable = (config)=>{
|
|
17
21
|
const fieldsToAdd = new Map();
|
|
22
|
+
const joinFieldPathsByCollection = new Map();
|
|
18
23
|
config.collections.forEach((collection)=>{
|
|
19
24
|
if (collection.orderable) {
|
|
20
25
|
const currentFields = fieldsToAdd.get(collection) || [];
|
|
@@ -47,23 +52,27 @@ import { generateKeyBetween, generateNKeysBetween } from './fractional-indexing.
|
|
|
47
52
|
const currentFields = fieldsToAdd.get(relationshipCollection) || [];
|
|
48
53
|
// @ts-expect-error ref is untyped
|
|
49
54
|
const prefix = parentRef?.prefix ? `${parentRef.prefix}_` : '';
|
|
55
|
+
const joinOrderableFieldName = `_${field.collection}_${prefix}${field.name}_order`;
|
|
50
56
|
fieldsToAdd.set(relationshipCollection, [
|
|
51
57
|
...currentFields,
|
|
52
|
-
|
|
58
|
+
joinOrderableFieldName
|
|
53
59
|
]);
|
|
60
|
+
const currentJoinFieldPaths = joinFieldPathsByCollection.get(relationshipCollection.slug) || new Map();
|
|
61
|
+
currentJoinFieldPaths.set(joinOrderableFieldName, field.on);
|
|
62
|
+
joinFieldPathsByCollection.set(relationshipCollection.slug, currentJoinFieldPaths);
|
|
54
63
|
}
|
|
55
64
|
},
|
|
56
65
|
fields: collection.fields
|
|
57
66
|
});
|
|
58
67
|
});
|
|
59
68
|
Array.from(fieldsToAdd.entries()).forEach(([collection, orderableFields])=>{
|
|
60
|
-
addOrderableFieldsAndHook(collection, orderableFields);
|
|
69
|
+
addOrderableFieldsAndHook(collection, orderableFields, joinFieldPathsByCollection);
|
|
61
70
|
});
|
|
62
71
|
if (fieldsToAdd.size > 0) {
|
|
63
|
-
addOrderableEndpoint(config);
|
|
72
|
+
addOrderableEndpoint(config, joinFieldPathsByCollection);
|
|
64
73
|
}
|
|
65
74
|
};
|
|
66
|
-
export const addOrderableFieldsAndHook = (collection, orderableFieldNames)=>{
|
|
75
|
+
export const addOrderableFieldsAndHook = (collection, orderableFieldNames, joinFieldPathsByCollection)=>{
|
|
67
76
|
// 1. Add field
|
|
68
77
|
orderableFieldNames.forEach((orderableFieldName)=>{
|
|
69
78
|
const orderField = {
|
|
@@ -99,6 +108,13 @@ export const addOrderableFieldsAndHook = (collection, orderableFieldNames)=>{
|
|
|
99
108
|
const orderBeforeChangeHook = async ({ data, originalDoc, req })=>{
|
|
100
109
|
for (const orderableFieldName of orderableFieldNames){
|
|
101
110
|
if (!data[orderableFieldName] && !originalDoc?.[orderableFieldName]) {
|
|
111
|
+
const joinScopeWhere = getJoinScopeWhereFromDocData({
|
|
112
|
+
collectionSlug: collection.slug,
|
|
113
|
+
data,
|
|
114
|
+
joinFieldPathsByCollection,
|
|
115
|
+
orderableFieldName,
|
|
116
|
+
originalDoc
|
|
117
|
+
});
|
|
102
118
|
const lastDoc = await req.payload.find({
|
|
103
119
|
collection: collection.slug,
|
|
104
120
|
depth: 0,
|
|
@@ -109,11 +125,14 @@ export const addOrderableFieldsAndHook = (collection, orderableFieldNames)=>{
|
|
|
109
125
|
[orderableFieldName]: true
|
|
110
126
|
},
|
|
111
127
|
sort: `-${orderableFieldName}`,
|
|
112
|
-
where:
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
128
|
+
where: combineWhereConstraints([
|
|
129
|
+
{
|
|
130
|
+
[orderableFieldName]: {
|
|
131
|
+
exists: true
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
joinScopeWhere ?? undefined
|
|
135
|
+
])
|
|
117
136
|
});
|
|
118
137
|
const lastOrderValue = lastDoc.docs[0]?.[orderableFieldName] || null;
|
|
119
138
|
data[orderableFieldName] = generateKeyBetween(lastOrderValue, null);
|
|
@@ -123,7 +142,7 @@ export const addOrderableFieldsAndHook = (collection, orderableFieldNames)=>{
|
|
|
123
142
|
};
|
|
124
143
|
collection.hooks.beforeChange.push(orderBeforeChangeHook);
|
|
125
144
|
};
|
|
126
|
-
export const addOrderableEndpoint = (config)=>{
|
|
145
|
+
export const addOrderableEndpoint = (config, joinFieldPathsByCollection)=>{
|
|
127
146
|
// 3. Add endpoint
|
|
128
147
|
const reorderHandler = async (req)=>{
|
|
129
148
|
const body = await req.json?.();
|
|
@@ -169,6 +188,13 @@ export const addOrderableEndpoint = (config)=>{
|
|
|
169
188
|
status: 400
|
|
170
189
|
});
|
|
171
190
|
}
|
|
191
|
+
const { joinScopeWhere, targetDoc } = await getJoinScopeContext({
|
|
192
|
+
collectionSlug: collection.slug,
|
|
193
|
+
joinFieldPathsByCollection,
|
|
194
|
+
orderableFieldName,
|
|
195
|
+
req,
|
|
196
|
+
target
|
|
197
|
+
});
|
|
172
198
|
// Prevent reordering if user doesn't have editing permissions
|
|
173
199
|
if (collection.access?.update) {
|
|
174
200
|
await executeAccess({
|
|
@@ -196,11 +222,14 @@ export const addOrderableEndpoint = (config)=>{
|
|
|
196
222
|
select: {
|
|
197
223
|
[orderableFieldName]: true
|
|
198
224
|
},
|
|
199
|
-
where:
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
225
|
+
where: combineWhereConstraints([
|
|
226
|
+
{
|
|
227
|
+
[orderableFieldName]: {
|
|
228
|
+
exists: false
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
joinScopeWhere ?? undefined
|
|
232
|
+
])
|
|
204
233
|
});
|
|
205
234
|
await initTransaction(req);
|
|
206
235
|
// We cannot update all documents in a single operation with `payload.update`,
|
|
@@ -244,20 +273,14 @@ export const addOrderableEndpoint = (config)=>{
|
|
|
244
273
|
});
|
|
245
274
|
}
|
|
246
275
|
const targetId = target.id;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
select: {
|
|
256
|
-
[orderableFieldName]: true
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
targetKey = beforeDoc?.[orderableFieldName] || null;
|
|
260
|
-
}
|
|
276
|
+
const targetKey = await resolvePendingTargetKey({
|
|
277
|
+
collectionSlug: collection.slug,
|
|
278
|
+
orderableFieldName,
|
|
279
|
+
req,
|
|
280
|
+
targetDoc,
|
|
281
|
+
targetID: targetId,
|
|
282
|
+
targetKey: target.key
|
|
283
|
+
});
|
|
261
284
|
// The reason the endpoint does not receive this docId as an argument is that there
|
|
262
285
|
// are situations where the user may not see or know what the next or previous one is. For
|
|
263
286
|
// example, access control restrictions, if docBefore is the last one on the page, etc.
|
|
@@ -270,11 +293,14 @@ export const addOrderableEndpoint = (config)=>{
|
|
|
270
293
|
[orderableFieldName]: true
|
|
271
294
|
},
|
|
272
295
|
sort: newKeyWillBe === 'greater' ? orderableFieldName : `-${orderableFieldName}`,
|
|
273
|
-
where:
|
|
274
|
-
|
|
275
|
-
[
|
|
276
|
-
|
|
277
|
-
|
|
296
|
+
where: combineWhereConstraints([
|
|
297
|
+
{
|
|
298
|
+
[orderableFieldName]: {
|
|
299
|
+
[newKeyWillBe === 'greater' ? 'greater_than' : 'less_than']: targetKey
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
joinScopeWhere ?? undefined
|
|
303
|
+
])
|
|
278
304
|
});
|
|
279
305
|
const adjacentDocKey = adjacentDoc.docs?.[0]?.[orderableFieldName] || null;
|
|
280
306
|
// Currently N (= docsToMove.length) is always 1. Maybe in the future we will
|