mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 08:13:56 +10:00
chore: implemented feedback + a small refactoring
This commit is contained in:
@ -3,7 +3,7 @@ import { ApiTokenForm } from '~/components/forms/token';
|
|||||||
export default function ApiToken() {
|
export default function ApiToken() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-medium">API Token</h3>
|
<h3 className="text-lg font-medium">API Tokens</h3>
|
||||||
|
|
||||||
<p className="text-muted-foreground mt-2 text-sm">
|
<p className="text-muted-foreground mt-2 text-sm">
|
||||||
On this page, you can create new API tokens and manage the existing ones.
|
On this page, you can create new API tokens and manage the existing ones.
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { useRouter } from 'next/navigation';
|
|||||||
|
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { Loader } from 'lucide-react';
|
import { Loader } from 'lucide-react';
|
||||||
|
import { DateTime } from 'luxon';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import type { z } from 'zod';
|
import type { z } from 'zod';
|
||||||
|
|
||||||
@ -139,23 +140,13 @@ export const ApiTokenForm = ({ className }: ApiTokenFormProps) => {
|
|||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
Created:{' '}
|
Created:{' '}
|
||||||
{token.createdAt
|
{token.createdAt
|
||||||
? new Date(token.createdAt).toLocaleDateString(undefined, {
|
? DateTime.fromJSDate(token.createdAt).toLocaleString(DateTime.DATETIME_FULL)
|
||||||
weekday: 'long',
|
|
||||||
year: 'numeric',
|
|
||||||
month: 'long',
|
|
||||||
day: 'numeric',
|
|
||||||
})
|
|
||||||
: 'N/A'}
|
: 'N/A'}
|
||||||
</p>
|
</p>
|
||||||
<p className="mb-4 text-sm">
|
<p className="mb-4 text-sm">
|
||||||
Expires:{' '}
|
Expires:{' '}
|
||||||
{token.expires
|
{token.expires
|
||||||
? new Date(token.expires).toLocaleDateString(undefined, {
|
? DateTime.fromJSDate(token.createdAt).toLocaleString(DateTime.DATETIME_FULL)
|
||||||
weekday: 'long',
|
|
||||||
year: 'numeric',
|
|
||||||
month: 'long',
|
|
||||||
day: 'numeric',
|
|
||||||
})
|
|
||||||
: 'N/A'}
|
: 'N/A'}
|
||||||
</p>
|
</p>
|
||||||
<DeleteTokenDialog
|
<DeleteTokenDialog
|
||||||
|
|||||||
@ -12,27 +12,20 @@ import { getPresignPostUrl } from '@documenso/lib/universal/upload/server-action
|
|||||||
import { contract } from '@documenso/trpc/api-contract/contract';
|
import { contract } from '@documenso/trpc/api-contract/contract';
|
||||||
import { createNextRoute, createNextRouter } from '@documenso/trpc/server/public-api/ts-rest';
|
import { createNextRoute, createNextRouter } from '@documenso/trpc/server/public-api/ts-rest';
|
||||||
|
|
||||||
const validateUserToken = async (token: string) => {
|
|
||||||
try {
|
|
||||||
return await checkUserFromToken({ token });
|
|
||||||
} catch (e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const router = createNextRoute(contract, {
|
const router = createNextRoute(contract, {
|
||||||
getDocuments: async (args) => {
|
getDocuments: async (args) => {
|
||||||
const page = Number(args.query.page) || 1;
|
const page = Number(args.query.page) || 1;
|
||||||
const perPage = Number(args.query.perPage) || 10;
|
const perPage = Number(args.query.perPage) || 10;
|
||||||
const { authorization } = args.headers;
|
const { authorization } = args.headers;
|
||||||
|
let user;
|
||||||
|
|
||||||
const user = await validateUserToken(authorization);
|
try {
|
||||||
|
user = await checkUserFromToken({ token: authorization });
|
||||||
if (!user) {
|
} catch (e) {
|
||||||
return {
|
return {
|
||||||
status: 401,
|
status: 401,
|
||||||
body: {
|
body: {
|
||||||
message: 'Unauthorized',
|
message: e.message,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -50,14 +43,15 @@ const router = createNextRoute(contract, {
|
|||||||
getDocument: async (args) => {
|
getDocument: async (args) => {
|
||||||
const { id: documentId } = args.params;
|
const { id: documentId } = args.params;
|
||||||
const { authorization } = args.headers;
|
const { authorization } = args.headers;
|
||||||
|
let user;
|
||||||
|
|
||||||
const user = await validateUserToken(authorization);
|
try {
|
||||||
|
user = await checkUserFromToken({ token: authorization });
|
||||||
if (!user) {
|
} catch (e) {
|
||||||
return {
|
return {
|
||||||
status: 401,
|
status: 401,
|
||||||
body: {
|
body: {
|
||||||
message: 'Unauthorized',
|
message: e.message,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -82,13 +76,15 @@ const router = createNextRoute(contract, {
|
|||||||
const { id: documentId } = args.params;
|
const { id: documentId } = args.params;
|
||||||
const { authorization } = args.headers;
|
const { authorization } = args.headers;
|
||||||
|
|
||||||
const user = await validateUserToken(authorization);
|
let user;
|
||||||
|
|
||||||
if (!user) {
|
try {
|
||||||
|
user = await checkUserFromToken({ token: authorization });
|
||||||
|
} catch (e) {
|
||||||
return {
|
return {
|
||||||
status: 401,
|
status: 401,
|
||||||
body: {
|
body: {
|
||||||
message: 'Unauthorized',
|
message: e.message,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -141,14 +137,15 @@ const router = createNextRoute(contract, {
|
|||||||
const { authorization } = args.headers;
|
const { authorization } = args.headers;
|
||||||
const { id } = args.params;
|
const { id } = args.params;
|
||||||
const { body } = args;
|
const { body } = args;
|
||||||
|
let user;
|
||||||
|
|
||||||
const user = await validateUserToken(authorization);
|
try {
|
||||||
|
user = await checkUserFromToken({ token: authorization });
|
||||||
if (!user) {
|
} catch (e) {
|
||||||
return {
|
return {
|
||||||
status: 401,
|
status: 401,
|
||||||
body: {
|
body: {
|
||||||
message: 'Unauthorized',
|
message: e.message,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,3 +3,5 @@ export const ONE_MINUTE = ONE_SECOND * 60;
|
|||||||
export const ONE_HOUR = ONE_MINUTE * 60;
|
export const ONE_HOUR = ONE_MINUTE * 60;
|
||||||
export const ONE_DAY = ONE_HOUR * 24;
|
export const ONE_DAY = ONE_HOUR * 24;
|
||||||
export const ONE_WEEK = ONE_DAY * 7;
|
export const ONE_WEEK = ONE_DAY * 7;
|
||||||
|
export const ONE_MONTH = ONE_DAY * 30;
|
||||||
|
export const ONE_YEAR = ONE_DAY * 365;
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import crypto from 'crypto';
|
|||||||
import { prisma } from '@documenso/prisma';
|
import { prisma } from '@documenso/prisma';
|
||||||
|
|
||||||
// temporary choice for testing only
|
// temporary choice for testing only
|
||||||
import { ONE_WEEK } from '../../constants/time';
|
import { ONE_YEAR } from '../../constants/time';
|
||||||
|
|
||||||
type CreateApiTokenInput = {
|
type CreateApiTokenInput = {
|
||||||
userId: number;
|
userId: number;
|
||||||
@ -22,7 +22,7 @@ export const createApiToken = async ({ userId, tokenName }: CreateApiTokenInput)
|
|||||||
token: tokenHash,
|
token: tokenHash,
|
||||||
name: tokenName,
|
name: tokenName,
|
||||||
userId,
|
userId,
|
||||||
expires: new Date(Date.now() + ONE_WEEK),
|
expires: new Date(Date.now() + ONE_YEAR),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { prisma } from '@documenso/prisma';
|
import { prisma } from '@documenso/prisma';
|
||||||
|
|
||||||
export const checkUserFromToken = async ({ token }: { token: string }) => {
|
export const checkUserFromToken = async ({ token }: { token: string }) => {
|
||||||
const user = await prisma.user.findFirstOrThrow({
|
const user = await prisma.user.findFirst({
|
||||||
where: {
|
where: {
|
||||||
ApiToken: {
|
ApiToken: {
|
||||||
some: {
|
some: {
|
||||||
@ -9,7 +9,20 @@ export const checkUserFromToken = async ({ token }: { token: string }) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
include: {
|
||||||
|
ApiToken: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
throw new Error('Token not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokenObject = user.ApiToken.find((apiToken) => apiToken.token === token);
|
||||||
|
|
||||||
|
if (!tokenObject || new Date(tokenObject.expires) < new Date()) {
|
||||||
|
throw new Error('The API token has expired');
|
||||||
|
}
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user