Skip to content

Commit b082344

Browse files
authored
fix: don't allow dav access control credentials (#3084)
1 parent 760d5d3 commit b082344

2 files changed

Lines changed: 8 additions & 25 deletions

File tree

src/backend/controllers/auth/AuthController.ts

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
*/
1919

2020
import bcrypt from 'bcrypt';
21-
import crypto from 'node:crypto';
2221
import type { Request, RequestHandler, Response } from 'express';
22+
import crypto from 'node:crypto';
2323
import { v4 as uuidv4 } from 'uuid';
2424
import validator from 'validator';
2525
import { Controller, Get, Post } from '../../core/http/decorators.js';
@@ -41,8 +41,8 @@ import {
4141
createSecret as otpCreateSecret,
4242
verify as verifyOtp,
4343
} from '../../services/auth/OTPUtil.js';
44-
import { cleanEmail, isBlockedEmail } from '../../util/email.js';
4544
import { sessionCookieFlags } from '../../util/cookieFlags.js';
45+
import { cleanEmail, isBlockedEmail } from '../../util/email.js';
4646
import { generate_identifier } from '../../util/identifier.js';
4747
import { getTaskbarItems } from '../../util/taskbarItems.js';
4848
import {
@@ -94,7 +94,6 @@ export class AuthController extends PuterController {
9494
// ── Login ───────────────────────────────────────────────────────
9595

9696
@Post('/login', {
97-
subdomain: ['api', ''],
9897
captcha: true,
9998
rateLimit: { scope: 'login', limit: 10, window: 15 * 60_000 },
10099
})
@@ -191,7 +190,6 @@ export class AuthController extends PuterController {
191190
// ── Login: OTP verification ─────────────────────────────────────
192191

193192
@Post('/login/otp', {
194-
subdomain: ['api', ''],
195193
captcha: true,
196194
rateLimit: {
197195
scope: 'login-otp',
@@ -246,7 +244,6 @@ export class AuthController extends PuterController {
246244
// ── Login: recovery code ────────────────────────────────────────
247245

248246
@Post('/login/recovery-code', {
249-
subdomain: ['api', ''],
250247
captcha: true,
251248
rateLimit: {
252249
scope: 'login-recovery',
@@ -314,7 +311,6 @@ export class AuthController extends PuterController {
314311
// ── Signup ──────────────────────────────────────────────────────
315312

316313
@Post('/signup', {
317-
subdomain: ['api', ''],
318314
captcha: true,
319315
rateLimit: { scope: 'signup', limit: 10, window: 15 * 60_000 },
320316
})
@@ -707,14 +703,13 @@ export class AuthController extends PuterController {
707703
// ── Logout ──────────────────────────────────────────────────────
708704

709705
@Post('/logout', {
710-
subdomain: ['api', ''],
711706
requireAuth: true,
712707
allowUnconfirmed: true,
713708
antiCsrf: true,
714709
})
715710
async handleLogout(req: Request, res: Response): Promise<void> {
716711
// Clear the session cookie
717-
res.clearCookie(this.config.cookie_name);
712+
res.clearCookie(this.config.cookie_name!);
718713

719714
// Remove the session (fire-and-forget)
720715
if (req.token) {
@@ -1552,7 +1547,6 @@ export class AuthController extends PuterController {
15521547
// ── Anti-CSRF token generation ──────────────────────────────────
15531548

15541549
@Get('/get-anticsrf-token', {
1555-
subdomain: '',
15561550
requireAuth: true,
15571551
allowUnconfirmed: true,
15581552
})
@@ -2326,7 +2320,6 @@ export class AuthController extends PuterController {
23262320
// ── Session helpers ─────────────────────────────────────────────
23272321

23282322
@Get('/get-gui-token', {
2329-
subdomain: ['api', ''],
23302323
requireUserActor: true,
23312324
allowUnconfirmed: true,
23322325
})
@@ -2348,7 +2341,6 @@ export class AuthController extends PuterController {
23482341
}
23492342

23502343
@Get('/session/sync-cookie', {
2351-
subdomain: ['api', ''],
23522344
requireUserActor: true,
23532345
allowUnconfirmed: true,
23542346
})
@@ -2382,7 +2374,7 @@ export class AuthController extends PuterController {
23822374

23832375
async handleDeleteOwnUser(req: Request, res: Response): Promise<void> {
23842376
const userId = req.actor!.user.id!;
2385-
res.clearCookie(this.config.cookie_name);
2377+
res.clearCookie(this.config.cookie_name!);
23862378
res.clearCookie('puter_revalidation');
23872379
await this.#cascadeDeleteUser(userId);
23882380
res.json({ success: true });
@@ -2442,7 +2434,6 @@ export class AuthController extends PuterController {
24422434
router.post(
24432435
'/user-protected/change-password',
24442436
{
2445-
subdomain: ['api', ''],
24462437
requireUserActor: true,
24472438
rateLimit: {
24482439
scope: 'passwd',
@@ -2462,7 +2453,6 @@ export class AuthController extends PuterController {
24622453
router.post(
24632454
'/user-protected/change-username',
24642455
{
2465-
subdomain: ['api', ''],
24662456
requireUserActor: true,
24672457
requireVerified: true,
24682458
rateLimit: {
@@ -2483,7 +2473,6 @@ export class AuthController extends PuterController {
24832473
router.post(
24842474
'/user-protected/change-email',
24852475
{
2486-
subdomain: ['api', ''],
24872476
requireUserActor: true,
24882477
rateLimit: {
24892478
scope: 'change-email-start',
@@ -2503,7 +2492,6 @@ export class AuthController extends PuterController {
25032492
router.post(
25042493
'/user-protected/disable-2fa',
25052494
{
2506-
subdomain: ['api', ''],
25072495
requireUserActor: true,
25082496
rateLimit: {
25092497
scope: 'disable-2fa',
@@ -2523,7 +2511,6 @@ export class AuthController extends PuterController {
25232511
router.post(
25242512
'/user-protected/delete-own-user',
25252513
{
2526-
subdomain: ['api', ''],
25272514
requireUserActor: true,
25282515
allowUnconfirmed: true,
25292516
middleware: [

src/backend/server.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -368,13 +368,10 @@ export class PuterServer {
368368
* `#materializeRoute` as those options ship.
369369
*/
370370
#installGlobalMiddleware() {
371-
// ── Cookie parsing ──────────────────────────────────────────
372371
this.#app.use(cookieParser());
373372

374-
// ── Compression ─────────────────────────────────────────────
375373
this.#app.use(compression());
376374

377-
// ── Security headers (helmet) ───────────────────────────────
378375
this.#app.use(helmet.noSniff());
379376
this.#app.use(helmet.hsts());
380377
this.#app.use(helmet.ieNoOpen());
@@ -615,19 +612,18 @@ export class PuterServer {
615612
this.#app.use((req, res, next) => {
616613
const origin = req.headers.origin;
617614
const subdomain = req.subdomains?.[req.subdomains.length - 1];
618-
const isApiOrDav = subdomain === 'api' || subdomain === 'dav';
619615

620616
// Allow any origin. puter.js is meant to be consumed from
621617
// arbitrary third-party sites, so reflect the caller's origin
622618
// (or fall back to `*` for non-browser clients).
623619
res.setHeader('Access-Control-Allow-Origin', origin ?? '*');
624620
if (origin) res.vary('Origin');
625621

626-
// Credentials require a specific (non-`*`) Allow-Origin, which
627-
// we just set when an origin was present. Enable on API/DAV
628-
// so cookie-auth works cross-origin.
629-
if (isApiOrDav && origin) {
622+
// Sticky cookies require api to allow credentials, but only for the API subdomain, and be careful not to set any other credentials on it
623+
if (subdomain === 'api' && origin) {
630624
res.setHeader('Access-Control-Allow-Credentials', 'true');
625+
} else if (subdomain === 'dav') {
626+
res.setHeader('Access-Control-Allow-Credentials', 'false');
631627
}
632628

633629
res.setHeader('Access-Control-Allow-Methods', allowedMethods);

0 commit comments

Comments
 (0)