mirror of
https://github.com/strapi/strapi.git
synced 2025-11-27 15:40:36 +00:00
Merge branch 'main' into features/deits
This commit is contained in:
commit
e10ac14726
@ -198,38 +198,73 @@ const cleanOrderColumns = async ({ id, attribute, db, inverseRelIds, transaction
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle databases that don't support window function ROW_NUMBER (here it's MySQL 5)
|
||||||
|
if (!strapi.db.dialect.supportsWindowFunctions()) {
|
||||||
|
await cleanOrderColumnsForOldDatabases({ id, attribute, db, inverseRelIds, transaction: trx });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { joinTable } = attribute;
|
||||||
|
const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = joinTable;
|
||||||
|
const update = [];
|
||||||
|
const updateBinding = [];
|
||||||
|
const select = ['??'];
|
||||||
|
const selectBinding = ['id'];
|
||||||
|
const where = [];
|
||||||
|
const whereBinding = [];
|
||||||
|
|
||||||
|
if (hasOrderColumn(attribute) && id) {
|
||||||
|
update.push('?? = b.src_order');
|
||||||
|
updateBinding.push(orderColumnName);
|
||||||
|
select.push('ROW_NUMBER() OVER (PARTITION BY ?? ORDER BY ??) AS src_order');
|
||||||
|
selectBinding.push(joinColumn.name, orderColumnName);
|
||||||
|
where.push('?? = ?');
|
||||||
|
whereBinding.push(joinColumn.name, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasInverseOrderColumn(attribute) && !isEmpty(inverseRelIds)) {
|
||||||
|
update.push('?? = b.inv_order');
|
||||||
|
updateBinding.push(inverseOrderColumnName);
|
||||||
|
select.push('ROW_NUMBER() OVER (PARTITION BY ?? ORDER BY ??) AS inv_order');
|
||||||
|
selectBinding.push(inverseJoinColumn.name, inverseOrderColumnName);
|
||||||
|
where.push(`?? IN (${inverseRelIds.map(() => '?').join(', ')})`);
|
||||||
|
whereBinding.push(inverseJoinColumn.name, ...inverseRelIds);
|
||||||
|
}
|
||||||
|
|
||||||
switch (strapi.db.dialect.client) {
|
switch (strapi.db.dialect.client) {
|
||||||
case 'mysql':
|
case 'mysql':
|
||||||
await cleanOrderColumnsForInnoDB({ id, attribute, db, inverseRelIds, transaction: trx });
|
// Here it's MariaDB and MySQL 8
|
||||||
|
await db
|
||||||
|
.getConnection()
|
||||||
|
.raw(
|
||||||
|
`UPDATE
|
||||||
|
?? as a,
|
||||||
|
(
|
||||||
|
SELECT ${select.join(', ')}
|
||||||
|
FROM ??
|
||||||
|
WHERE ${where.join(' OR ')}
|
||||||
|
) AS b
|
||||||
|
SET ${update.join(', ')}
|
||||||
|
WHERE b.id = a.id`,
|
||||||
|
[joinTable.name, ...selectBinding, joinTable.name, ...whereBinding, ...updateBinding]
|
||||||
|
)
|
||||||
|
.transacting(trx);
|
||||||
break;
|
break;
|
||||||
|
/*
|
||||||
|
UPDATE
|
||||||
|
:joinTable: as a,
|
||||||
|
(
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
ROW_NUMBER() OVER ( PARTITION BY :joinColumn: ORDER BY :orderColumn:) AS src_order,
|
||||||
|
ROW_NUMBER() OVER ( PARTITION BY :inverseJoinColumn: ORDER BY :inverseOrderColumn:) AS inv_order
|
||||||
|
FROM :joinTable:
|
||||||
|
WHERE :joinColumn: = :id OR :inverseJoinColumn: IN (:inverseRelIds)
|
||||||
|
) AS b
|
||||||
|
SET :orderColumn: = b.src_order, :inverseOrderColumn: = b.inv_order
|
||||||
|
WHERE b.id = a.id;
|
||||||
|
*/
|
||||||
default: {
|
default: {
|
||||||
const { joinTable } = attribute;
|
|
||||||
const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = joinTable;
|
|
||||||
const update = [];
|
|
||||||
const updateBinding = [];
|
|
||||||
const select = ['??'];
|
|
||||||
const selectBinding = ['id'];
|
|
||||||
const where = [];
|
|
||||||
const whereBinding = [];
|
|
||||||
|
|
||||||
if (hasOrderColumn(attribute) && id) {
|
|
||||||
update.push('?? = b.src_order');
|
|
||||||
updateBinding.push(orderColumnName);
|
|
||||||
select.push('ROW_NUMBER() OVER (PARTITION BY ?? ORDER BY ??) AS src_order');
|
|
||||||
selectBinding.push(joinColumn.name, orderColumnName);
|
|
||||||
where.push('?? = ?');
|
|
||||||
whereBinding.push(joinColumn.name, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasInverseOrderColumn(attribute) && !isEmpty(inverseRelIds)) {
|
|
||||||
update.push('?? = b.inv_order');
|
|
||||||
updateBinding.push(inverseOrderColumnName);
|
|
||||||
select.push('ROW_NUMBER() OVER (PARTITION BY ?? ORDER BY ??) AS inv_order');
|
|
||||||
selectBinding.push(inverseJoinColumn.name, inverseOrderColumnName);
|
|
||||||
where.push(`?? IN (${inverseRelIds.map(() => '?').join(', ')})`);
|
|
||||||
whereBinding.push(inverseJoinColumn.name, ...inverseRelIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
const joinTableName = addSchema(joinTable.name);
|
const joinTableName = addSchema(joinTable.name);
|
||||||
|
|
||||||
// raw query as knex doesn't allow updating from a subquery
|
// raw query as knex doesn't allow updating from a subquery
|
||||||
@ -249,17 +284,17 @@ const cleanOrderColumns = async ({ id, attribute, db, inverseRelIds, transaction
|
|||||||
.transacting(trx);
|
.transacting(trx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
`UPDATE :joinTable: as a
|
UPDATE :joinTable: as a
|
||||||
SET :orderColumn: = b.src_order, :inverseOrderColumn: = b.inv_order
|
SET :orderColumn: = b.src_order, :inverseOrderColumn: = b.inv_order
|
||||||
FROM (
|
FROM (
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
ROW_NUMBER() OVER ( PARTITION BY :joinColumn: ORDER BY :orderColumn:) AS src_order,
|
ROW_NUMBER() OVER ( PARTITION BY :joinColumn: ORDER BY :orderColumn:) AS src_order,
|
||||||
ROW_NUMBER() OVER ( PARTITION BY :inverseJoinColumn: ORDER BY :inverseOrderColumn:) AS inv_order
|
ROW_NUMBER() OVER ( PARTITION BY :inverseJoinColumn: ORDER BY :inverseOrderColumn:) AS inv_order
|
||||||
FROM :joinTable:
|
FROM :joinTable:
|
||||||
WHERE :joinColumn: = :id OR :inverseJoinColumn: IN (:inverseRelIds)
|
WHERE :joinColumn: = :id OR :inverseJoinColumn: IN (:inverseRelIds)
|
||||||
) AS b
|
) AS b
|
||||||
WHERE b.id = a.id`,
|
WHERE b.id = a.id;
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,9 +302,9 @@ const cleanOrderColumns = async ({ id, attribute, db, inverseRelIds, transaction
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure that orders are following a 1, 2, 3 sequence, without gap.
|
* Ensure that orders are following a 1, 2, 3 sequence, without gap.
|
||||||
* The use of a temporary table instead of a window function makes the query compatible with MySQL 5 and prevents some deadlocks to happen in innoDB databases
|
* The use of a session variable instead of a window function makes the query compatible with MySQL 5
|
||||||
*/
|
*/
|
||||||
const cleanOrderColumnsForInnoDB = async ({
|
const cleanOrderColumnsForOldDatabases = async ({
|
||||||
id,
|
id,
|
||||||
attribute,
|
attribute,
|
||||||
db,
|
db,
|
||||||
@ -279,96 +314,68 @@ const cleanOrderColumnsForInnoDB = async ({
|
|||||||
const { joinTable } = attribute;
|
const { joinTable } = attribute;
|
||||||
const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = joinTable;
|
const { joinColumn, inverseJoinColumn, orderColumnName, inverseOrderColumnName } = joinTable;
|
||||||
|
|
||||||
const now = new Date().valueOf();
|
const randomSuffix = `${new Date().valueOf()}_${randomBytes(16).toString('hex')}`;
|
||||||
const randomHex = randomBytes(16).toString('hex');
|
|
||||||
|
|
||||||
if (hasOrderColumn(attribute) && id) {
|
if (hasOrderColumn(attribute) && id) {
|
||||||
const tempOrderTableName = `orderTable_${now}_${randomHex}`;
|
// raw query as knex doesn't allow updating from a subquery
|
||||||
try {
|
// https://github.com/knex/knex/issues/2504
|
||||||
await db.connection
|
const orderVar = `order_${randomSuffix}`;
|
||||||
.raw(
|
await db.connection.raw(`SET @${orderVar} = 0;`).transacting(trx);
|
||||||
`
|
await db.connection
|
||||||
CREATE TABLE :tempOrderTableName:
|
.raw(
|
||||||
SELECT
|
`UPDATE :joinTableName: as a, (
|
||||||
id,
|
SELECT id, (@${orderVar}:=@${orderVar} + 1) AS src_order
|
||||||
(
|
FROM :joinTableName:
|
||||||
SELECT count(*)
|
WHERE :joinColumnName: = :id
|
||||||
FROM :joinTableName: b
|
ORDER BY :orderColumnName:
|
||||||
WHERE a.:orderColumnName: >= b.:orderColumnName: AND a.:joinColumnName: = b.:joinColumnName: AND a.:joinColumnName: = :id
|
) AS b
|
||||||
) AS src_order
|
SET :orderColumnName: = b.src_order
|
||||||
FROM :joinTableName: a
|
WHERE a.id = b.id
|
||||||
WHERE a.:joinColumnName: = :id
|
AND a.:joinColumnName: = :id`,
|
||||||
`,
|
{
|
||||||
{
|
joinTableName: joinTable.name,
|
||||||
tempOrderTableName,
|
orderColumnName,
|
||||||
joinTableName: joinTable.name,
|
joinColumnName: joinColumn.name,
|
||||||
orderColumnName,
|
id,
|
||||||
joinColumnName: joinColumn.name,
|
}
|
||||||
id,
|
)
|
||||||
}
|
.transacting(trx);
|
||||||
)
|
|
||||||
.transacting(trx);
|
|
||||||
|
|
||||||
// raw query as knex doesn't allow updating from a subquery
|
|
||||||
// https://github.com/knex/knex/issues/2504
|
|
||||||
await db.connection
|
|
||||||
.raw(
|
|
||||||
`UPDATE ?? as a, (SELECT * FROM ??) AS b
|
|
||||||
SET ?? = b.src_order
|
|
||||||
WHERE a.id = b.id`,
|
|
||||||
[joinTable.name, tempOrderTableName, orderColumnName]
|
|
||||||
)
|
|
||||||
.transacting(trx);
|
|
||||||
} finally {
|
|
||||||
await db.connection.raw(`DROP TABLE IF EXISTS ??`, [tempOrderTableName]).transacting(trx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasInverseOrderColumn(attribute) && !isEmpty(inverseRelIds)) {
|
if (hasInverseOrderColumn(attribute) && !isEmpty(inverseRelIds)) {
|
||||||
const tempInvOrderTableName = `invOrderTable_${now}_${randomHex}`;
|
const orderVar = `order_${randomSuffix}`;
|
||||||
try {
|
const columnVar = `col_${randomSuffix}`;
|
||||||
await db.connection
|
await db.connection.raw(`SET @${orderVar} = 0;`).transacting(trx);
|
||||||
.raw(
|
await db.connection
|
||||||
`
|
.raw(
|
||||||
CREATE TABLE ??
|
`UPDATE ?? as a, (
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
(
|
@${orderVar}:=CASE WHEN @${columnVar} = ?? THEN @${orderVar} + 1 ELSE 1 END AS inv_order,
|
||||||
SELECT count(*)
|
@${columnVar}:=?? ??
|
||||||
FROM ?? b
|
FROM ?? a
|
||||||
WHERE a.?? >= b.?? AND a.?? = b.?? AND a.?? IN (${inverseRelIds
|
WHERE ?? IN(${inverseRelIds.map(() => '?').join(', ')})
|
||||||
.map(() => '?')
|
ORDER BY ??, ??
|
||||||
.join(', ')})
|
) AS b
|
||||||
) AS inv_order
|
SET ?? = b.inv_order
|
||||||
FROM ?? a
|
WHERE a.id = b.id
|
||||||
WHERE a.?? IN (${inverseRelIds.map(() => '?').join(', ')})
|
AND a.?? IN(${inverseRelIds.map(() => '?').join(', ')})`,
|
||||||
`,
|
[
|
||||||
[
|
joinTable.name,
|
||||||
tempInvOrderTableName,
|
inverseJoinColumn.name,
|
||||||
joinTable.name,
|
inverseJoinColumn.name,
|
||||||
inverseOrderColumnName,
|
inverseJoinColumn.name,
|
||||||
inverseOrderColumnName,
|
joinTable.name,
|
||||||
inverseJoinColumn.name,
|
inverseJoinColumn.name,
|
||||||
inverseJoinColumn.name,
|
...inverseRelIds,
|
||||||
inverseJoinColumn.name,
|
inverseJoinColumn.name,
|
||||||
...inverseRelIds,
|
joinColumn.name,
|
||||||
joinTable.name,
|
inverseOrderColumnName,
|
||||||
inverseJoinColumn.name,
|
inverseJoinColumn.name,
|
||||||
...inverseRelIds,
|
...inverseRelIds,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
.transacting(trx);
|
.transacting(trx);
|
||||||
await db.connection
|
|
||||||
.raw(
|
|
||||||
`UPDATE ?? as a, (SELECT * FROM ??) AS b
|
|
||||||
SET ?? = b.inv_order
|
|
||||||
WHERE a.id = b.id`,
|
|
||||||
[joinTable.name, tempInvOrderTableName, inverseOrderColumnName]
|
|
||||||
)
|
|
||||||
.transacting(trx);
|
|
||||||
} finally {
|
|
||||||
await db.connection.raw(`DROP TABLE IF EXISTS ??`, [tempInvOrderTableName]).transacting(trx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -43,9 +43,10 @@ const createComponents = async (uid, data) => {
|
|||||||
throw new Error('Expected an array to create repeatable component');
|
throw new Error('Expected an array to create repeatable component');
|
||||||
}
|
}
|
||||||
|
|
||||||
const components = await Promise.all(
|
const components = [];
|
||||||
componentValue.map((value) => createComponent(componentUID, value))
|
for (const value of componentValue) {
|
||||||
);
|
components.push(await createComponent(componentUID, value));
|
||||||
|
}
|
||||||
|
|
||||||
componentBody[attributeName] = components.map(({ id }) => {
|
componentBody[attributeName] = components.map(({ id }) => {
|
||||||
return {
|
return {
|
||||||
@ -77,18 +78,19 @@ const createComponents = async (uid, data) => {
|
|||||||
throw new Error('Expected an array to create repeatable component');
|
throw new Error('Expected an array to create repeatable component');
|
||||||
}
|
}
|
||||||
|
|
||||||
componentBody[attributeName] = await Promise.all(
|
const dynamicZoneData = [];
|
||||||
dynamiczoneValues.map(async (value) => {
|
for (const value of dynamiczoneValues) {
|
||||||
const { id } = await createComponent(value.__component, value);
|
const { id } = await createComponent(value.__component, value);
|
||||||
return {
|
dynamicZoneData.push({
|
||||||
id,
|
id,
|
||||||
__component: value.__component,
|
__component: value.__component,
|
||||||
__pivot: {
|
__pivot: {
|
||||||
field: attributeName,
|
field: attributeName,
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
})
|
}
|
||||||
);
|
|
||||||
|
componentBody[attributeName] = dynamicZoneData;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -137,9 +139,10 @@ const updateComponents = async (uid, entityToUpdate, data) => {
|
|||||||
throw new Error('Expected an array to create repeatable component');
|
throw new Error('Expected an array to create repeatable component');
|
||||||
}
|
}
|
||||||
|
|
||||||
const components = await Promise.all(
|
const components = [];
|
||||||
componentValue.map((value) => updateOrCreateComponent(componentUID, value))
|
for (const value of componentValue) {
|
||||||
);
|
components.push(await updateOrCreateComponent(componentUID, value));
|
||||||
|
}
|
||||||
|
|
||||||
componentBody[attributeName] = components.filter(_.negate(_.isNil)).map(({ id }) => {
|
componentBody[attributeName] = components.filter(_.negate(_.isNil)).map(({ id }) => {
|
||||||
return {
|
return {
|
||||||
@ -173,19 +176,19 @@ const updateComponents = async (uid, entityToUpdate, data) => {
|
|||||||
throw new Error('Expected an array to create repeatable component');
|
throw new Error('Expected an array to create repeatable component');
|
||||||
}
|
}
|
||||||
|
|
||||||
componentBody[attributeName] = await Promise.all(
|
const dynamicZoneData = [];
|
||||||
dynamiczoneValues.map(async (value) => {
|
for (const value of dynamiczoneValues) {
|
||||||
const { id } = await updateOrCreateComponent(value.__component, value);
|
const { id } = await updateOrCreateComponent(value.__component, value);
|
||||||
|
dynamicZoneData.push({
|
||||||
|
id,
|
||||||
|
__component: value.__component,
|
||||||
|
__pivot: {
|
||||||
|
field: attributeName,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
componentBody[attributeName] = dynamicZoneData;
|
||||||
id,
|
|
||||||
__component: value.__component,
|
|
||||||
__pivot: {
|
|
||||||
field: attributeName,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -287,14 +290,14 @@ const deleteComponents = async (uid, entityToDelete, { loadComponents = true } =
|
|||||||
|
|
||||||
if (attribute.type === 'component') {
|
if (attribute.type === 'component') {
|
||||||
const { component: componentUID } = attribute;
|
const { component: componentUID } = attribute;
|
||||||
await Promise.all(
|
for (const subValue of _.castArray(value)) {
|
||||||
_.castArray(value).map((subValue) => deleteComponent(componentUID, subValue))
|
await deleteComponent(componentUID, subValue);
|
||||||
);
|
}
|
||||||
} else {
|
} else {
|
||||||
// delete dynamic zone components
|
// delete dynamic zone components
|
||||||
await Promise.all(
|
for (const subValue of _.castArray(value)) {
|
||||||
_.castArray(value).map((subValue) => deleteComponent(subValue.__component, subValue))
|
await deleteComponent(subValue.__component, subValue);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@ -228,6 +228,7 @@ module.exports = ({ strapi }) => ({
|
|||||||
const formats = await generateResponsiveFormats(fileData);
|
const formats = await generateResponsiveFormats(fileData);
|
||||||
if (Array.isArray(formats) && formats.length > 0) {
|
if (Array.isArray(formats) && formats.length > 0) {
|
||||||
for (const format of formats) {
|
for (const format of formats) {
|
||||||
|
// eslint-disable-next-line no-continue
|
||||||
if (!format) continue;
|
if (!format) continue;
|
||||||
uploadPromises.push(uploadResponsiveFormat(format));
|
uploadPromises.push(uploadResponsiveFormat(format));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,9 @@ const syncLocalizations = async (entry, { model }) => {
|
|||||||
return strapi.query(model.uid).update({ where: { id }, data: { localizations } });
|
return strapi.query(model.uid).update({ where: { id }, data: { localizations } });
|
||||||
};
|
};
|
||||||
|
|
||||||
await Promise.all(entry.localizations.map(({ id }) => updateLocalization(id)));
|
for (const localization of entry.localizations) {
|
||||||
|
await updateLocalization(localization.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -56,7 +58,9 @@ const syncNonLocalizedAttributes = async (entry, { model }) => {
|
|||||||
return strapi.entityService.update(model.uid, id, { data: nonLocalizedAttributes });
|
return strapi.entityService.update(model.uid, id, { data: nonLocalizedAttributes });
|
||||||
};
|
};
|
||||||
|
|
||||||
await Promise.all(entry.localizations.map(({ id }) => updateLocalization(id)));
|
for (const localization of entry.localizations) {
|
||||||
|
await updateLocalization(localization.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -173,6 +173,21 @@ const forms = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
intlLabel: {
|
||||||
|
id: getTrad({ id: 'PopUpForm.Providers.jwksurl.label' }),
|
||||||
|
defaultMessage: 'JWKS URL',
|
||||||
|
},
|
||||||
|
name: 'jwksurl',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: textPlaceholder,
|
||||||
|
size: 12,
|
||||||
|
validations: {
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|||||||
@ -31,6 +31,7 @@
|
|||||||
"@strapi/utils": "4.5.6",
|
"@strapi/utils": "4.5.6",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"grant-koa": "5.4.8",
|
"grant-koa": "5.4.8",
|
||||||
|
"jwk-to-pem": "2.0.5",
|
||||||
"jsonwebtoken": "9.0.0",
|
"jsonwebtoken": "9.0.0",
|
||||||
"koa": "^2.13.4",
|
"koa": "^2.13.4",
|
||||||
"koa2-ratelimit": "^1.1.2",
|
"koa2-ratelimit": "^1.1.2",
|
||||||
@ -64,4 +65,4 @@
|
|||||||
"required": true,
|
"required": true,
|
||||||
"kind": "plugin"
|
"kind": "plugin"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2,6 +2,48 @@
|
|||||||
|
|
||||||
const { strict: assert } = require('assert');
|
const { strict: assert } = require('assert');
|
||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
|
const jwkToPem = require('jwk-to-pem');
|
||||||
|
|
||||||
|
const getCognitoPayload = async ({ idToken, jwksUrl, purest }) => {
|
||||||
|
const {
|
||||||
|
header: { kid },
|
||||||
|
payload,
|
||||||
|
} = jwt.decode(idToken, { complete: true });
|
||||||
|
|
||||||
|
if (!payload || !kid) {
|
||||||
|
throw new Error('The provided token is not valid');
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
cognito: {
|
||||||
|
discovery: {
|
||||||
|
origin: jwksUrl.origin,
|
||||||
|
path: jwksUrl.pathname,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const cognito = purest({ provider: 'cognito', config });
|
||||||
|
// get the JSON Web Key (JWK) for the user pool
|
||||||
|
const { body: jwk } = await cognito('discovery').request();
|
||||||
|
// Get the key with the same Key ID as the provided token
|
||||||
|
const key = jwk.keys.find(({ kid: jwkKid }) => jwkKid === kid);
|
||||||
|
const pem = jwkToPem(key);
|
||||||
|
|
||||||
|
// https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html
|
||||||
|
const decodedToken = await new Promise((resolve, reject) => {
|
||||||
|
jwt.verify(idToken, pem, { algorithms: ['RS256'] }, (err, decodedToken) => {
|
||||||
|
if (err) {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
resolve(decodedToken);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return decodedToken;
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error('There was an error verifying the token');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getInitialProviders = ({ purest }) => ({
|
const getInitialProviders = ({ purest }) => ({
|
||||||
async discord({ accessToken }) {
|
async discord({ accessToken }) {
|
||||||
@ -19,19 +61,14 @@ const getInitialProviders = ({ purest }) => ({
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async cognito({ query }) {
|
async cognito({ query, providers }) {
|
||||||
// get the id_token
|
const jwksUrl = new URL(providers.cognito.jwksurl);
|
||||||
const idToken = query.id_token;
|
const idToken = query.id_token;
|
||||||
// decode the jwt token
|
const tokenPayload = await getCognitoPayload({ idToken, jwksUrl, purest });
|
||||||
const tokenPayload = jwt.decode(idToken);
|
return {
|
||||||
if (!tokenPayload) {
|
username: tokenPayload['cognito:username'],
|
||||||
throw new Error('unable to decode jwt token');
|
email: tokenPayload.email,
|
||||||
} else {
|
};
|
||||||
return {
|
|
||||||
username: tokenPayload['cognito:username'],
|
|
||||||
email: tokenPayload.email,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
async facebook({ accessToken }) {
|
async facebook({ accessToken }) {
|
||||||
const facebook = purest({ provider: 'facebook' });
|
const facebook = purest({ provider: 'facebook' });
|
||||||
|
|||||||
@ -14847,7 +14847,7 @@ jwa@^2.0.0:
|
|||||||
ecdsa-sig-formatter "1.0.11"
|
ecdsa-sig-formatter "1.0.11"
|
||||||
safe-buffer "^5.0.1"
|
safe-buffer "^5.0.1"
|
||||||
|
|
||||||
jwk-to-pem@^2.0.5:
|
jwk-to-pem@2.0.5, jwk-to-pem@^2.0.5:
|
||||||
version "2.0.5"
|
version "2.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz#151310bcfbcf731adc5ad9f379cbc8b395742906"
|
resolved "https://registry.yarnpkg.com/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz#151310bcfbcf731adc5ad9f379cbc8b395742906"
|
||||||
integrity sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==
|
integrity sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user