mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
27 Commits
@auth/core
...
firebase-a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bb06892bd | ||
|
|
1cd5cbb02a | ||
|
|
63099497ec | ||
|
|
b3caf1c4b2 | ||
|
|
c3c951bcdf | ||
|
|
bd336aa4af | ||
|
|
c4f2f345c8 | ||
|
|
b57ae5fdf3 | ||
|
|
f5514534ee | ||
|
|
927280231d | ||
|
|
e289670add | ||
|
|
ff0d74cd9a | ||
|
|
5a77198d4f | ||
|
|
e6952127a6 | ||
|
|
f96be2bdcd | ||
|
|
0f370ff1ac | ||
|
|
22cdfbac2b | ||
|
|
b9d9888e38 | ||
|
|
dfc85454b4 | ||
|
|
498acdb9fa | ||
|
|
900c51cb65 | ||
|
|
e4d5591718 | ||
|
|
c3400b4a7c | ||
|
|
4d1159639e | ||
|
|
b32d4f2fd6 | ||
|
|
6a7bd5d58b | ||
|
|
70f03435be |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@next-auth/dynamodb-adapter",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"version": "3.0.0",
|
||||
"version": "1.2.0",
|
||||
"description": "AWS DynamoDB adapter for next-auth.",
|
||||
"keywords": [
|
||||
"next-auth",
|
||||
@@ -9,18 +9,11 @@
|
||||
"oauth",
|
||||
"dynamodb"
|
||||
],
|
||||
"type": "module",
|
||||
"types": "./index.d.ts",
|
||||
"homepage": "https://authjs.dev",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"import": "./index.js"
|
||||
}
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -33,10 +26,7 @@
|
||||
},
|
||||
"files": [
|
||||
"README.md",
|
||||
"index.js",
|
||||
"index.d.ts",
|
||||
"index.d.ts.map",
|
||||
"src"
|
||||
"dist"
|
||||
],
|
||||
"author": "Pol Marnette",
|
||||
"license": "ISC",
|
||||
@@ -51,11 +41,7 @@
|
||||
"@next-auth/adapter-test": "workspace:*",
|
||||
"@next-auth/tsconfig": "workspace:*",
|
||||
"@shelf/jest-dynamodb": "^2.1.0",
|
||||
"@types/uuid": "^9.0.0",
|
||||
"jest": "^27.4.3",
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": "^9.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { v4 as uuid } from "uuid"
|
||||
import { randomBytes } from "crypto"
|
||||
|
||||
import type {
|
||||
BatchWriteCommandInput,
|
||||
@@ -12,12 +12,16 @@ import type {
|
||||
VerificationToken,
|
||||
} from "next-auth/adapters"
|
||||
|
||||
import { format, generateUpdateExpression } from "./utils"
|
||||
|
||||
export { format, generateUpdateExpression }
|
||||
|
||||
export interface DynamoDBAdapterOptions {
|
||||
tableName?: string
|
||||
partitionKey?: string
|
||||
sortKey?: string
|
||||
indexName?: string
|
||||
indexPartitionKey?: string
|
||||
tableName?: string,
|
||||
partitionKey?: string,
|
||||
sortKey?: string,
|
||||
indexName?: string,
|
||||
indexPartitionKey?: string,
|
||||
indexSortKey?: string
|
||||
}
|
||||
|
||||
@@ -26,17 +30,17 @@ export function DynamoDBAdapter(
|
||||
options?: DynamoDBAdapterOptions
|
||||
): Adapter {
|
||||
const TableName = options?.tableName ?? "next-auth"
|
||||
const pk = options?.partitionKey ?? "pk"
|
||||
const sk = options?.sortKey ?? "sk"
|
||||
const IndexName = options?.indexName ?? "GSI1"
|
||||
const GSI1PK = options?.indexPartitionKey ?? "GSI1PK"
|
||||
const GSI1SK = options?.indexSortKey ?? "GSI1SK"
|
||||
const pk = options?.partitionKey ?? 'pk'
|
||||
const sk = options?.sortKey ?? 'sk'
|
||||
const IndexName = options?.indexName ?? 'GSI1'
|
||||
const GSI1PK = options?.indexPartitionKey ?? 'GSI1PK'
|
||||
const GSI1SK = options?.indexSortKey ?? 'GSI1SK'
|
||||
|
||||
return {
|
||||
async createUser(data) {
|
||||
const user: AdapterUser = {
|
||||
...(data as any),
|
||||
id: uuid(),
|
||||
id: randomBytes(16).toString("hex"),
|
||||
}
|
||||
|
||||
await client.put({
|
||||
@@ -46,8 +50,8 @@ export function DynamoDBAdapter(
|
||||
[pk]: `USER#${user.id}`,
|
||||
[sk]: `USER#${user.id}`,
|
||||
type: "USER",
|
||||
[GSI1PK]: `USER#${user.email}`,
|
||||
[GSI1SK]: `USER#${user.email}`,
|
||||
[GSI1PK]: `USER#${user.email as string}`,
|
||||
[GSI1SK]: `USER#${user.email as string}`,
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -161,7 +165,7 @@ export function DynamoDBAdapter(
|
||||
async linkAccount(data) {
|
||||
const item = {
|
||||
...data,
|
||||
id: uuid(),
|
||||
id: randomBytes(16).toString("hex"),
|
||||
[pk]: `USER#${data.userId}`,
|
||||
[sk]: `ACCOUNT#${data.provider}#${data.providerAccountId}`,
|
||||
[GSI1PK]: `ACCOUNT#${data.provider}`,
|
||||
@@ -225,7 +229,7 @@ export function DynamoDBAdapter(
|
||||
},
|
||||
async createSession(data) {
|
||||
const session = {
|
||||
id: uuid(),
|
||||
id: randomBytes(16).toString("hex"),
|
||||
...data,
|
||||
}
|
||||
await client.put({
|
||||
@@ -323,73 +327,3 @@ export function DynamoDBAdapter(
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/honeinc/is-iso-date/blob/master/index.js
|
||||
const isoDateRE =
|
||||
/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/
|
||||
function isDate(value: any) {
|
||||
return value && isoDateRE.test(value) && !isNaN(Date.parse(value))
|
||||
}
|
||||
|
||||
const format = {
|
||||
/** Takes a plain old JavaScript object and turns it into a Dynamodb object */
|
||||
to(object: Record<string, any>) {
|
||||
const newObject: Record<string, unknown> = {}
|
||||
for (const key in object) {
|
||||
const value = object[key]
|
||||
if (value instanceof Date) {
|
||||
// DynamoDB requires the TTL attribute be a UNIX timestamp (in secs).
|
||||
if (key === "expires") newObject[key] = value.getTime() / 1000
|
||||
else newObject[key] = value.toISOString()
|
||||
} else newObject[key] = value
|
||||
}
|
||||
return newObject
|
||||
},
|
||||
/** Takes a Dynamo object and returns a plain old JavaScript object */
|
||||
from<T = Record<string, unknown>>(object?: Record<string, any>): T | null {
|
||||
if (!object) return null
|
||||
const newObject: Record<string, unknown> = {}
|
||||
for (const key in object) {
|
||||
// Filter DynamoDB specific attributes so it doesn't get passed to core,
|
||||
// to avoid revealing the type of database
|
||||
if (["pk", "sk", "GSI1PK", "GSI1SK"].includes(key)) continue
|
||||
|
||||
const value = object[key]
|
||||
|
||||
if (isDate(value)) newObject[key] = new Date(value)
|
||||
// hack to keep type property in account
|
||||
else if (key === "type" && ["SESSION", "VT", "USER"].includes(value))
|
||||
continue
|
||||
// The expires property is stored as a UNIX timestamp in seconds, but
|
||||
// JavaScript needs it in milliseconds, so multiply by 1000.
|
||||
else if (key === "expires" && typeof value === "number")
|
||||
newObject[key] = new Date(value * 1000)
|
||||
else newObject[key] = value
|
||||
}
|
||||
return newObject as T
|
||||
},
|
||||
}
|
||||
|
||||
function generateUpdateExpression(object: Record<string, any>): {
|
||||
UpdateExpression: string
|
||||
ExpressionAttributeNames: Record<string, string>
|
||||
ExpressionAttributeValues: Record<string, unknown>
|
||||
} {
|
||||
const formatedSession = format.to(object)
|
||||
let UpdateExpression = "set"
|
||||
const ExpressionAttributeNames: Record<string, string> = {}
|
||||
const ExpressionAttributeValues: Record<string, unknown> = {}
|
||||
for (const property in formatedSession) {
|
||||
UpdateExpression += ` #${property} = :${property},`
|
||||
ExpressionAttributeNames["#" + property] = property
|
||||
ExpressionAttributeValues[":" + property] = formatedSession[property]
|
||||
}
|
||||
UpdateExpression = UpdateExpression.slice(0, -1)
|
||||
return {
|
||||
UpdateExpression,
|
||||
ExpressionAttributeNames,
|
||||
ExpressionAttributeValues,
|
||||
}
|
||||
}
|
||||
|
||||
export { format, generateUpdateExpression }
|
||||
|
||||
67
packages/adapter-dynamodb/src/utils.ts
Normal file
67
packages/adapter-dynamodb/src/utils.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
// https://github.com/honeinc/is-iso-date/blob/master/index.js
|
||||
const isoDateRE =
|
||||
/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/
|
||||
function isDate(value: any) {
|
||||
return value && isoDateRE.test(value) && !isNaN(Date.parse(value))
|
||||
}
|
||||
|
||||
export const format = {
|
||||
/** Takes a plain old JavaScript object and turns it into a Dynamodb object */
|
||||
to(object: Record<string, any>) {
|
||||
const newObject: Record<string, unknown> = {}
|
||||
for (const key in object) {
|
||||
const value = object[key]
|
||||
if (value instanceof Date) {
|
||||
// DynamoDB requires the TTL attribute be a UNIX timestamp (in secs).
|
||||
if (key === "expires") newObject[key] = value.getTime() / 1000
|
||||
else newObject[key] = value.toISOString()
|
||||
} else newObject[key] = value
|
||||
}
|
||||
return newObject
|
||||
},
|
||||
/** Takes a Dynamo object and returns a plain old JavaScript object */
|
||||
from<T = Record<string, unknown>>(object?: Record<string, any>): T | null {
|
||||
if (!object) return null
|
||||
const newObject: Record<string, unknown> = {}
|
||||
for (const key in object) {
|
||||
// Filter DynamoDB specific attributes so it doesn't get passed to core,
|
||||
// to avoid revealing the type of database
|
||||
if (["pk", "sk", "GSI1PK", "GSI1SK"].includes(key)) continue
|
||||
|
||||
const value = object[key]
|
||||
|
||||
if (isDate(value)) newObject[key] = new Date(value)
|
||||
// hack to keep type property in account
|
||||
else if (key === "type" && ["SESSION", "VT", "USER"].includes(value))
|
||||
continue
|
||||
// The expires property is stored as a UNIX timestamp in seconds, but
|
||||
// JavaScript needs it in milliseconds, so multiply by 1000.
|
||||
else if (key === "expires" && typeof value === "number")
|
||||
newObject[key] = new Date(value * 1000)
|
||||
else newObject[key] = value
|
||||
}
|
||||
return newObject as T
|
||||
},
|
||||
}
|
||||
|
||||
export function generateUpdateExpression(object: Record<string, any>): {
|
||||
UpdateExpression: string
|
||||
ExpressionAttributeNames: Record<string, string>
|
||||
ExpressionAttributeValues: Record<string, unknown>
|
||||
} {
|
||||
const formatedSession = format.to(object)
|
||||
let UpdateExpression = "set"
|
||||
const ExpressionAttributeNames: Record<string, string> = {}
|
||||
const ExpressionAttributeValues: Record<string, unknown> = {}
|
||||
for (const property in formatedSession) {
|
||||
UpdateExpression += ` #${property} = :${property},`
|
||||
ExpressionAttributeNames["#" + property] = property
|
||||
ExpressionAttributeValues[":" + property] = formatedSession[property]
|
||||
}
|
||||
UpdateExpression = UpdateExpression.slice(0, -1)
|
||||
return {
|
||||
UpdateExpression,
|
||||
ExpressionAttributeNames,
|
||||
ExpressionAttributeValues,
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { format } from "../src/"
|
||||
import { format } from "../src/utils"
|
||||
|
||||
describe("dynamodb utils.format", () => {
|
||||
it("format.to() preserves non-Date non-expires properties", () => {
|
||||
|
||||
@@ -2,15 +2,7 @@
|
||||
"extends": "@next-auth/tsconfig/tsconfig.adapters.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": ".",
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"skipDefaultLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
"stripInternal": true,
|
||||
"declarationMap": true,
|
||||
"declaration": true
|
||||
"outDir": "dist"
|
||||
},
|
||||
"exclude": ["tests", "dist", "jest.config.js", "jest-dynamodb-config.js"]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@next-auth/firebase-adapter",
|
||||
"version": "2.0.0",
|
||||
"version": "1.0.3",
|
||||
"description": "Firebase adapter for next-auth.",
|
||||
"homepage": "https://authjs.dev",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
@@ -52,4 +52,4 @@
|
||||
"jest": "^29.3.1",
|
||||
"next-auth": "workspace:*"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@auth/core",
|
||||
"version": "0.4.0",
|
||||
"version": "0.3.0",
|
||||
"description": "Authentication for the Web.",
|
||||
"keywords": [
|
||||
"authentication",
|
||||
@@ -27,7 +27,7 @@
|
||||
"types": "./index.d.ts",
|
||||
"files": [
|
||||
"*.js",
|
||||
"*.d.ts*",
|
||||
"*.d.ts",
|
||||
"lib",
|
||||
"providers",
|
||||
"src"
|
||||
@@ -93,4 +93,4 @@
|
||||
"postcss": "8.4.19",
|
||||
"postcss-nested": "6.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@auth/sveltekit",
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.0",
|
||||
"description": "Authentication for SvelteKit.",
|
||||
"keywords": [
|
||||
"authentication",
|
||||
|
||||
17
pnpm-lock.yaml
generated
17
pnpm-lock.yaml
generated
@@ -243,19 +243,14 @@ importers:
|
||||
'@next-auth/adapter-test': workspace:*
|
||||
'@next-auth/tsconfig': workspace:*
|
||||
'@shelf/jest-dynamodb': ^2.1.0
|
||||
'@types/uuid': ^9.0.0
|
||||
jest: ^27.4.3
|
||||
next-auth: workspace:*
|
||||
uuid: ^9.0.0
|
||||
dependencies:
|
||||
uuid: 9.0.0
|
||||
devDependencies:
|
||||
'@aws-sdk/client-dynamodb': 3.113.0
|
||||
'@aws-sdk/lib-dynamodb': 3.113.0_eb2z3hhrjl3qvyc6ecmpo2nhva
|
||||
'@next-auth/adapter-test': link:../adapter-test
|
||||
'@next-auth/tsconfig': link:../tsconfig
|
||||
'@shelf/jest-dynamodb': 2.2.4_qsruu6yolbxs4rh6ixjhkibvwu
|
||||
'@types/uuid': 9.0.0
|
||||
jest: 27.5.1
|
||||
next-auth: link:../next-auth
|
||||
|
||||
@@ -12755,10 +12750,6 @@ packages:
|
||||
resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==}
|
||||
dev: true
|
||||
|
||||
/@types/uuid/9.0.0:
|
||||
resolution: {integrity: sha512-kr90f+ERiQtKWMz5rP32ltJ/BtULDI5RVO0uavn1HQUOwjx0R1h0rnDYNL0CepF1zL5bSY6FISAfd9tOdDhU5Q==}
|
||||
dev: true
|
||||
|
||||
/@types/validator/13.7.3:
|
||||
resolution: {integrity: sha512-DNviAE5OUcZ5s+XEQHRhERLg8fOp8gSgvyJ4aaFASx5wwaObm+PBwTIMXiOFm1QrSee5oYwEAYb7LMzX2O88gA==}
|
||||
dev: true
|
||||
@@ -13750,8 +13741,10 @@ packages:
|
||||
indent-string: 4.0.0
|
||||
dev: true
|
||||
|
||||
/ajv-formats/2.1.1:
|
||||
/ajv-formats/2.1.1_ajv@8.11.0:
|
||||
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
|
||||
peerDependencies:
|
||||
ajv: ^8.0.0
|
||||
peerDependenciesMeta:
|
||||
ajv:
|
||||
optional: true
|
||||
@@ -19542,7 +19535,7 @@ packages:
|
||||
dependencies:
|
||||
'@apidevtools/json-schema-ref-parser': 9.0.9
|
||||
ajv: 8.11.0
|
||||
ajv-formats: 2.1.1
|
||||
ajv-formats: 2.1.1_ajv@8.11.0
|
||||
body-parser: 1.20.0
|
||||
content-type: 1.0.4
|
||||
deep-freeze: 0.0.1
|
||||
@@ -30982,7 +30975,7 @@ packages:
|
||||
dependencies:
|
||||
'@types/json-schema': 7.0.11
|
||||
ajv: 8.11.0
|
||||
ajv-formats: 2.1.1
|
||||
ajv-formats: 2.1.1_ajv@8.11.0
|
||||
ajv-keywords: 5.1.0_ajv@8.11.0
|
||||
dev: true
|
||||
|
||||
|
||||
Reference in New Issue
Block a user