mirror of
https://github.com/freedbygrace/DynamoDNS.git
synced 2026-09-03 14:17:56 +00:00
Improve API token expiration handling by adding date and time validation and ensuring consistent expiresAt data type.
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 9111ef36-26c8-4085-84ca-a35dc1fec1b5 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7083d608-d6d3-4a6a-9a27-6286c5109627/97ca9771-6ea6-4874-95e0-c9ca04f36ec8.jpg
This commit is contained in:
@@ -79,7 +79,9 @@ const tokenFormSchema = z.object({
|
|||||||
role: z.string().min(1, "Role is required"),
|
role: z.string().min(1, "Role is required"),
|
||||||
expiresIn: z.string().optional(),
|
expiresIn: z.string().optional(),
|
||||||
customDate: z.date().optional(),
|
customDate: z.date().optional(),
|
||||||
customTime: z.string().optional(),
|
customTime: z.string().regex(/^([01]?[0-9]|2[0-3]):[0-5][0-9]$/, {
|
||||||
|
message: "Time must be in 24-hour format HH:MM"
|
||||||
|
}).optional(),
|
||||||
}).refine((data) => {
|
}).refine((data) => {
|
||||||
// If custom expiration is selected, a date must be provided
|
// If custom expiration is selected, a date must be provided
|
||||||
if (data.expiresIn === 'custom' && !data.customDate) {
|
if (data.expiresIn === 'custom' && !data.customDate) {
|
||||||
@@ -89,6 +91,19 @@ const tokenFormSchema = z.object({
|
|||||||
}, {
|
}, {
|
||||||
message: "Please select a date for the custom expiration",
|
message: "Please select a date for the custom expiration",
|
||||||
path: ["customDate"]
|
path: ["customDate"]
|
||||||
|
}).refine((data) => {
|
||||||
|
// If a custom date is provided, validate it's in the future
|
||||||
|
if (data.customDate) {
|
||||||
|
const now = new Date();
|
||||||
|
const dateOnly = new Date(data.customDate);
|
||||||
|
dateOnly.setHours(0, 0, 0, 0);
|
||||||
|
now.setHours(0, 0, 0, 0);
|
||||||
|
return dateOnly >= now;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}, {
|
||||||
|
message: "Expiration date must be in the future",
|
||||||
|
path: ["customDate"]
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function ApiTokensPage() {
|
export default function ApiTokensPage() {
|
||||||
|
|||||||
+42
-2
@@ -523,6 +523,20 @@ export class MemStorage implements IStorage {
|
|||||||
console.log("No expiresAt provided in token data");
|
console.log("No expiresAt provided in token data");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure expiresAt is either a Date object or null
|
||||||
|
let finalExpiresAt: Date | null = null;
|
||||||
|
if (expiresAt) {
|
||||||
|
if (expiresAt instanceof Date) {
|
||||||
|
finalExpiresAt = expiresAt;
|
||||||
|
} else if (typeof expiresAt === 'string') {
|
||||||
|
try {
|
||||||
|
finalExpiresAt = new Date(expiresAt);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Could not convert expiresAt string to Date:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const newToken: ApiToken = {
|
const newToken: ApiToken = {
|
||||||
id: numId.toString(),
|
id: numId.toString(),
|
||||||
name: token.name || "Unnamed Token",
|
name: token.name || "Unnamed Token",
|
||||||
@@ -532,7 +546,7 @@ export class MemStorage implements IStorage {
|
|||||||
role: token.role || 'readonly',
|
role: token.role || 'readonly',
|
||||||
createdBy: token.createdBy || "1",
|
createdBy: token.createdBy || "1",
|
||||||
isActive: token.isActive ?? true,
|
isActive: token.isActive ?? true,
|
||||||
expiresAt: expiresAt,
|
expiresAt: finalExpiresAt,
|
||||||
createdAt
|
createdAt
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -546,7 +560,33 @@ export class MemStorage implements IStorage {
|
|||||||
const token = await this.getApiToken(id);
|
const token = await this.getApiToken(id);
|
||||||
if (!token) return undefined;
|
if (!token) return undefined;
|
||||||
|
|
||||||
const updatedToken = { ...token, ...tokenData };
|
// Handle expiresAt specially to ensure it's a Date object or null
|
||||||
|
let finalExpiresAt = token.expiresAt;
|
||||||
|
if ('expiresAt' in tokenData) {
|
||||||
|
const newExpiresAt = tokenData.expiresAt;
|
||||||
|
if (newExpiresAt === null) {
|
||||||
|
finalExpiresAt = null;
|
||||||
|
} else if (newExpiresAt instanceof Date) {
|
||||||
|
finalExpiresAt = newExpiresAt;
|
||||||
|
} else if (typeof newExpiresAt === 'string') {
|
||||||
|
try {
|
||||||
|
finalExpiresAt = new Date(newExpiresAt);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Could not convert expiresAt string to Date:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove expiresAt to prevent type issues
|
||||||
|
const { expiresAt, ...otherData } = tokenData;
|
||||||
|
tokenData = otherData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedToken = {
|
||||||
|
...token,
|
||||||
|
...tokenData,
|
||||||
|
expiresAt: finalExpiresAt
|
||||||
|
};
|
||||||
|
|
||||||
this.apiTokensMap.set(numId, updatedToken);
|
this.apiTokensMap.set(numId, updatedToken);
|
||||||
return updatedToken;
|
return updatedToken;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user