diff --git a/messages/en-US.json b/messages/en-US.json index 16190316..5fe4417f 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -1231,7 +1231,7 @@ "securityKeyRemoveSuccess": "Security key removed successfully", "securityKeyRemoveError": "Failed to remove security key", "securityKeyLoadError": "Failed to load security keys", - "securityKeyLogin": "Sign in with security key", + "securityKeyLogin": "Continue with security key", "securityKeyAuthError": "Failed to authenticate with security key", "securityKeyRecommendation": "Register a backup security key on another device to ensure you always have access to your account.", "registering": "Registering...", diff --git a/public/screenshots/collage.png b/public/screenshots/collage.png deleted file mode 100644 index c791e7ea..00000000 Binary files a/public/screenshots/collage.png and /dev/null differ diff --git a/public/screenshots/create-api-key.png b/public/screenshots/create-api-key.png new file mode 100644 index 00000000..ad0ef6a4 Binary files /dev/null and b/public/screenshots/create-api-key.png differ diff --git a/public/screenshots/create-idp.png b/public/screenshots/create-idp.png new file mode 100644 index 00000000..e19ddec5 Binary files /dev/null and b/public/screenshots/create-idp.png differ diff --git a/public/screenshots/create-resource.png b/public/screenshots/create-resource.png new file mode 100644 index 00000000..3b21f22b Binary files /dev/null and b/public/screenshots/create-resource.png differ diff --git a/public/screenshots/create-share-link.png b/public/screenshots/create-share-link.png new file mode 100644 index 00000000..18849501 Binary files /dev/null and b/public/screenshots/create-share-link.png differ diff --git a/public/screenshots/create-site.png b/public/screenshots/create-site.png new file mode 100644 index 00000000..b5ff8048 Binary files /dev/null and b/public/screenshots/create-site.png differ diff --git a/public/screenshots/edit-resource.png b/public/screenshots/edit-resource.png new file mode 100644 index 00000000..2d21afa6 Binary files /dev/null and b/public/screenshots/edit-resource.png differ diff --git a/public/screenshots/hero.png b/public/screenshots/hero.png index 4e321ee1..86216cf6 100644 Binary files a/public/screenshots/hero.png and b/public/screenshots/hero.png differ diff --git a/public/screenshots/resource-auth.png b/public/screenshots/resource-auth.png new file mode 100644 index 00000000..e9d39f4c Binary files /dev/null and b/public/screenshots/resource-auth.png differ diff --git a/public/screenshots/resource-authentication.png b/public/screenshots/resource-authentication.png new file mode 100644 index 00000000..764cd616 Binary files /dev/null and b/public/screenshots/resource-authentication.png differ diff --git a/public/screenshots/resources.png b/public/screenshots/resources.png new file mode 100644 index 00000000..86216cf6 Binary files /dev/null and b/public/screenshots/resources.png differ diff --git a/public/screenshots/roles.png b/public/screenshots/roles.png new file mode 100644 index 00000000..09d27387 Binary files /dev/null and b/public/screenshots/roles.png differ diff --git a/public/screenshots/site-online.png b/public/screenshots/site-online.png new file mode 100644 index 00000000..0adef017 Binary files /dev/null and b/public/screenshots/site-online.png differ diff --git a/public/screenshots/sites.png b/public/screenshots/sites.png new file mode 100644 index 00000000..0aaa79d0 Binary files /dev/null and b/public/screenshots/sites.png differ diff --git a/public/screenshots/users.png b/public/screenshots/users.png new file mode 100644 index 00000000..91286e02 Binary files /dev/null and b/public/screenshots/users.png differ diff --git a/server/routers/external.ts b/server/routers/external.ts index d15a8297..e64d3456 100644 --- a/server/routers/external.ts +++ b/server/routers/external.ts @@ -815,7 +815,7 @@ authRouter.post( rateLimit({ windowMs: 15 * 60 * 1000, max: 15, - keyGenerator: (req) => `login:${req.body.email}`, + keyGenerator: (req) => `login:${req.body.email || req.ip}`, handler: (req, res, next) => { const message = `You can only log in ${15} times every ${15} minutes. Please try again later.`; return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message)); @@ -830,7 +830,7 @@ authRouter.post( rateLimit({ windowMs: 15 * 60 * 1000, max: 900, - keyGenerator: (req) => `newtGetToken:${req.body.newtId}`, + keyGenerator: (req) => `newtGetToken:${req.body.newtId || req.ip}`, handler: (req, res, next) => { const message = `You can only request a Newt token ${900} times every ${15} minutes. Please try again later.`; return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message)); @@ -844,7 +844,7 @@ authRouter.post( rateLimit({ windowMs: 15 * 60 * 1000, max: 900, - keyGenerator: (req) => `newtGetToken:${req.body.newtId}`, + keyGenerator: (req) => `newtGetToken:${req.body.newtId || req.ip}`, handler: (req, res, next) => { const message = `You can only request an Olm token ${900} times every ${15} minutes. Please try again later.`; return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message)); @@ -860,13 +860,7 @@ authRouter.post( windowMs: 15 * 60 * 1000, max: 15, keyGenerator: (req) => { - // user is authenticated, so we can use their userId; - // otherwise, they provide the email - if (req.body.email) { - return `signup:${req.body.email}`; - } else { - return `signup:${req.user!.userId}`; - } + return `signup:${req.body.email || req.user?.userId || req.ip}`; }, handler: (req, res, next) => { const message = `You can only enable 2FA ${15} times every ${15} minutes. Please try again later.`; @@ -882,13 +876,7 @@ authRouter.post( windowMs: 15 * 60 * 1000, max: 15, keyGenerator: (req) => { - // user is authenticated, so we can use their userId; - // otherwise, they provide the email - if (req.body.email) { - return `signup:${req.body.email}`; - } else { - return `signup:${req.user!.userId}`; - } + return `signup:${req.body.email || req.user?.userId || req.ip}`; }, handler: (req, res, next) => { const message = `You can only request a 2FA code ${15} times every ${15} minutes. Please try again later.`; @@ -896,7 +884,6 @@ authRouter.post( }, store: createStore() }), - auth.requestTotpSecret ); authRouter.post( @@ -905,7 +892,7 @@ authRouter.post( rateLimit({ windowMs: 15 * 60 * 1000, max: 15, - keyGenerator: (req) => `signup:${req.user!.userId}`, + keyGenerator: (req) => `signup:${req.user?.userId || req.ip}`, handler: (req, res, next) => { const message = `You can only disable 2FA ${15} times every ${15} minutes. Please try again later.`; return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message)); @@ -919,7 +906,7 @@ authRouter.post( rateLimit({ windowMs: 15 * 60 * 1000, max: 15, - keyGenerator: (req) => `signup:${req.body.email}`, + keyGenerator: (req) => `signup:${req.body.email || req.ip}`, handler: (req, res, next) => { const message = `You can only sign up ${15} times every ${15} minutes. Please try again later.`; return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message)); @@ -936,7 +923,7 @@ authRouter.post( rateLimit({ windowMs: 15 * 60 * 1000, max: 15, - keyGenerator: (req) => `requestEmailVerificationCode:${req.body.email}`, + keyGenerator: (req) => `requestEmailVerificationCode:${req.body.email || req.ip}`, handler: (req, res, next) => { const message = `You can only request an email verification code ${15} times every ${15} minutes. Please try again later.`; return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message)); @@ -957,7 +944,7 @@ authRouter.post( rateLimit({ windowMs: 15 * 60 * 1000, max: 15, - keyGenerator: (req) => `requestPasswordReset:${req.body.email}`, + keyGenerator: (req) => `requestPasswordReset:${req.body.email || req.ip}`, handler: (req, res, next) => { const message = `You can only request a password reset ${15} times every ${15} minutes. Please try again later.`; return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message)); @@ -972,7 +959,7 @@ authRouter.post( rateLimit({ windowMs: 15 * 60 * 1000, max: 15, - keyGenerator: (req) => `resetPassword:${req.body.email}`, + keyGenerator: (req) => `resetPassword:${req.body.email || req.ip}`, handler: (req, res, next) => { const message = `You can only request a password reset ${15} times every ${15} minutes. Please try again later.`; return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message)); @@ -988,7 +975,7 @@ authRouter.post( windowMs: 15 * 60 * 1000, max: 15, keyGenerator: (req) => - `authWithPassword:${req.ip}:${req.params.resourceId}`, + `authWithPassword:${req.ip}:${req.params.resourceId || req.ip}`, handler: (req, res, next) => { const message = `You can only authenticate with password ${15} times every ${15} minutes. Please try again later.`; return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message)); @@ -1003,7 +990,7 @@ authRouter.post( windowMs: 15 * 60 * 1000, max: 15, keyGenerator: (req) => - `authWithPincode:${req.ip}:${req.params.resourceId}`, + `authWithPincode:${req.ip}:${req.params.resourceId || req.ip}`, handler: (req, res, next) => { const message = `You can only authenticate with pincode ${15} times every ${15} minutes. Please try again later.`; return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message)); @@ -1050,7 +1037,7 @@ authRouter.post( rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 5, // Allow 5 security key registrations per 15 minutes - keyGenerator: (req) => `securityKeyRegister:${req.user!.userId}`, + keyGenerator: (req) => `securityKeyRegister:${req.user?.userId || req.ip}`, handler: (req, res, next) => { const message = `You can only register a security key ${5} times every ${15} minutes. Please try again later.`; return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message)); @@ -1070,11 +1057,7 @@ authRouter.post( windowMs: 15 * 60 * 1000, // 15 minutes max: 10, // Allow 10 authentication attempts per 15 minutes per IP keyGenerator: (req) => { - if (req.body.email) { - return `securityKeyAuth:${req.body.email}`; - } else { - return `securityKeyAuth:${req.ip}`; - } + return `securityKeyAuth:${req.body.email || req.ip}`; }, handler: (req, res, next) => { const message = `You can only attempt security key authentication ${10} times every ${15} minutes. Please try again later.`; @@ -1096,7 +1079,7 @@ authRouter.delete( rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 20, // Allow 10 authentication attempts per 15 minutes per IP - keyGenerator: (req) => `securityKeyAuth:${req.user!.userId}`, + keyGenerator: (req) => `securityKeyAuth:${req.user?.userId || req.ip}`, handler: (req, res, next) => { const message = `You can only delete a security key ${10} times every ${15} minutes. Please try again later.`; return next(createHttpError(HttpCode.TOO_MANY_REQUESTS, message)); diff --git a/src/app/auth/resource/[resourceId]/ResourceAuthPortal.tsx b/src/app/auth/resource/[resourceId]/ResourceAuthPortal.tsx index bf703309..c77c9e0b 100644 --- a/src/app/auth/resource/[resourceId]/ResourceAuthPortal.tsx +++ b/src/app/auth/resource/[resourceId]/ResourceAuthPortal.tsx @@ -291,6 +291,19 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {