Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/app/api/auth/backup-pin/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { NextResponse } from 'next/server';
import { randomBytes, scrypt as scryptCallback } from 'node:crypto';
import { promisify } from 'node:util';
import { createClient } from '@supabase/supabase-js';
import { supabaseAuthCookieName } from '@/lib/supabase/auth-cookie.js';
import { createServiceRoleClient } from '@/lib/supabase/service-role.js';

// node:crypto is required for scrypt, so pin this route to the Node runtime.
Expand Down Expand Up @@ -65,9 +66,9 @@ async function authenticateUser(request) {

let accessToken = null;

if (cookies['sb-xydzwxwsbgmznthiiscl-auth-token']) {
if (cookies[supabaseAuthCookieName()]) {
try {
let tokenData = cookies['sb-xydzwxwsbgmznthiiscl-auth-token'];
let tokenData = cookies[supabaseAuthCookieName()];
if (tokenData.startsWith('base64-')) {
tokenData = Buffer.from(tokenData.substring(7), 'base64').toString('utf-8');
}
Expand Down
7 changes: 4 additions & 3 deletions src/app/api/auth/backup-pin/route.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { supabaseAuthCookieName } from '@/lib/supabase/auth-cookie.js';
import { beforeEach, describe, expect, it, vi } from 'vitest';

import { createHash } from 'node:crypto';
Expand Down Expand Up @@ -83,7 +84,7 @@ describe('backup PIN cookie authentication', () => {
const response = await GET(
new Request('https://qrypt.chat/api/auth/backup-pin', {
headers: {
cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${cookieValue('access-token')};session=ignored`
cookie: `${supabaseAuthCookieName()}=${cookieValue('access-token')};session=ignored`
}
})
);
Expand All @@ -99,7 +100,7 @@ describe('backup PIN cookie authentication', () => {
const response = await GET(
new Request('https://qrypt.chat/api/auth/backup-pin', {
headers: {
cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${paddedCookieValue()}`
cookie: `${supabaseAuthCookieName()}=${paddedCookieValue()}`
}
})
);
Expand Down Expand Up @@ -130,7 +131,7 @@ describe('backup PIN cookie authentication', () => {
new Request('https://qrypt.chat/api/auth/backup-pin', {
headers: {
authorization: 'Bearer ',
cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${cookieValue('cookie-token')}`
cookie: `${supabaseAuthCookieName()}=${cookieValue('cookie-token')}`
}
})
);
Expand Down
5 changes: 3 additions & 2 deletions src/app/api/auth/key-backup/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import { NextResponse } from 'next/server';
import { createClient } from '@supabase/supabase-js';
import { supabaseAuthCookieName } from '@/lib/supabase/auth-cookie.js';
import { createServiceRoleClient } from '@/lib/supabase/service-role.js';

// Lazy service role client creation
Expand Down Expand Up @@ -61,9 +62,9 @@ async function authenticateUser(request) {
let accessToken = null;

// Try Supabase-specific cookies first
if (cookies['sb-xydzwxwsbgmznthiiscl-auth-token']) {
if (cookies[supabaseAuthCookieName()]) {
try {
let tokenData = cookies['sb-xydzwxwsbgmznthiiscl-auth-token'];
let tokenData = cookies[supabaseAuthCookieName()];
if (tokenData.startsWith('base64-')) {
tokenData = Buffer.from(tokenData.substring(7), 'base64').toString('utf-8');
}
Expand Down
7 changes: 4 additions & 3 deletions src/app/api/auth/key-backup/route.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { supabaseAuthCookieName } from '@/lib/supabase/auth-cookie.js';
import { beforeEach, describe, expect, it, vi } from 'vitest';

const mocks = vi.hoisted(() => ({
Expand Down Expand Up @@ -85,7 +86,7 @@ describe('key backup cookie authentication', () => {
const response = await GET(
new Request('https://qrypt.chat/api/auth/key-backup', {
headers: {
cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${cookieValue('access-token')};session=ignored`
cookie: `${supabaseAuthCookieName()}=${cookieValue('access-token')};session=ignored`
}
})
);
Expand All @@ -107,7 +108,7 @@ describe('key backup cookie authentication', () => {
const response = await GET(
new Request('https://qrypt.chat/api/auth/key-backup', {
headers: {
cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${paddedCookieValue()}`
cookie: `${supabaseAuthCookieName()}=${paddedCookieValue()}`
}
})
);
Expand Down Expand Up @@ -136,7 +137,7 @@ describe('key backup cookie authentication', () => {
new Request('https://qrypt.chat/api/auth/key-backup', {
headers: {
authorization: 'Bearer ',
cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${cookieValue('cookie-token')}`
cookie: `${supabaseAuthCookieName()}=${cookieValue('cookie-token')}`
}
})
);
Expand Down
5 changes: 3 additions & 2 deletions src/app/api/auth/salt/route.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { supabaseAuthCookieName } from '@/lib/supabase/auth-cookie.js';
import { beforeEach, describe, expect, it, vi } from 'vitest';

const mocks = vi.hoisted(() => ({
Expand Down Expand Up @@ -71,7 +72,7 @@ describe('salt cookie authentication', () => {
const response = await GET(
new Request('https://qrypt.chat/api/auth/salt', {
headers: {
cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${cookieValue('access-token')};session=ignored`
cookie: `${supabaseAuthCookieName()}=${cookieValue('access-token')};session=ignored`
}
})
);
Expand Down Expand Up @@ -104,7 +105,7 @@ describe('salt cookie authentication', () => {
new Request('https://qrypt.chat/api/auth/salt', {
headers: {
authorization: 'Bearer ',
cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${cookieValue('cookie-token')}`
cookie: `${supabaseAuthCookieName()}=${cookieValue('cookie-token')}`
}
})
);
Expand Down
5 changes: 3 additions & 2 deletions src/app/api/chat/conversations/[id]/participants/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import { NextResponse } from 'next/server';
import { createClient } from '@supabase/supabase-js';
import { supabaseAuthCookieName } from '@/lib/supabase/auth-cookie.js';
import { createServiceRoleClient } from '@/lib/supabase/service-role.js';

// Lazy service role client creation
Expand Down Expand Up @@ -50,10 +51,10 @@ async function authenticateUser(request) {
console.log('馃攼 Available cookies:', Object.keys(cookies));

// Try Supabase-specific cookies first
if (cookies['sb-xydzwxwsbgmznthiiscl-auth-token']) {
if (cookies[supabaseAuthCookieName()]) {
console.log('馃攼 Found Supabase auth token cookie');
try {
let tokenData = cookies['sb-xydzwxwsbgmznthiiscl-auth-token'];
let tokenData = cookies[supabaseAuthCookieName()];
if (tokenData.startsWith('base64-')) {
tokenData = Buffer.from(tokenData.substring(7), 'base64').toString('utf-8');
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { supabaseAuthCookieName } from '@/lib/supabase/auth-cookie.js';
import { beforeEach, describe, expect, it, vi } from 'vitest';

const mocks = vi.hoisted(() => ({
Expand Down Expand Up @@ -126,7 +127,7 @@ describe('GET /api/chat/conversations/[id]/participants', () => {
const { GET } = await import('./route.js');
const response = await GET(
new Request('https://qrypt.chat/api/chat/conversations/conversation-1/participants', {
headers: { cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${paddedCookieValue()}` }
headers: { cookie: `${supabaseAuthCookieName()}=${paddedCookieValue()}` }
}),
{ params: Promise.resolve({ id: 'conversation-1' }) }
);
Expand Down
5 changes: 3 additions & 2 deletions src/app/api/crypto/public-keys/all/route.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { NextResponse } from 'next/server';
import { createClient } from '@supabase/supabase-js';
import { supabaseAuthCookieName } from '@/lib/supabase/auth-cookie.js';

// Regular (anon) client used ONLY to validate the caller's JWT. Never use the
// service-role key for auth checks.
Expand Down Expand Up @@ -33,9 +34,9 @@ async function authenticateUser(request) {
let accessToken = null;

// Supabase-specific auth cookie first
if (cookies['sb-xydzwxwsbgmznthiiscl-auth-token']) {
if (cookies[supabaseAuthCookieName()]) {
try {
let tokenData = cookies['sb-xydzwxwsbgmznthiiscl-auth-token'];
let tokenData = cookies[supabaseAuthCookieName()];
if (tokenData.startsWith('base64-')) {
tokenData = Buffer.from(tokenData.substring(7), 'base64').toString('utf-8');
}
Expand Down
3 changes: 2 additions & 1 deletion src/app/api/crypto/public-keys/all/route.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { supabaseAuthCookieName } from '@/lib/supabase/auth-cookie.js';
import { beforeEach, describe, expect, it, vi } from 'vitest';

const mocks = vi.hoisted(() => ({
Expand Down Expand Up @@ -32,7 +33,7 @@ describe('all public keys cookie authentication', () => {
const response = await GET(
new Request('https://qrypt.chat/api/crypto/public-keys/all', {
headers: {
cookie: 'sb-xydzwxwsbgmznthiiscl-auth-token=base64-eyJhY2Nlc3NfdG9rZW4iOiJhYmMiLCJwYWRkaW5nIjoieCJ9==',
cookie: `${supabaseAuthCookieName()}=base64-eyJhY2Nlc3NfdG9rZW4iOiJhYmMiLCJwYWRkaW5nIjoieCJ9==`,
},
}),
);
Expand Down
5 changes: 3 additions & 2 deletions src/app/api/crypto/public-keys/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import { NextResponse } from 'next/server';
import { createClient } from '@supabase/supabase-js';
import { supabaseAuthCookieName } from '@/lib/supabase/auth-cookie.js';
import { createServiceRoleClient } from '@/lib/supabase/service-role.js';

// Lazy service role client creation
Expand Down Expand Up @@ -65,9 +66,9 @@ async function authenticateUser(request) {
let accessToken = null;

// Try Supabase-specific cookies first
if (cookies['sb-xydzwxwsbgmznthiiscl-auth-token']) {
if (cookies[supabaseAuthCookieName()]) {
try {
let tokenData = cookies['sb-xydzwxwsbgmznthiiscl-auth-token'];
let tokenData = cookies[supabaseAuthCookieName()];
if (tokenData.startsWith('base64-')) {
tokenData = Buffer.from(tokenData.substring(7), 'base64').toString('utf-8');
}
Expand Down
13 changes: 7 additions & 6 deletions src/app/api/crypto/public-keys/route.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { supabaseAuthCookieName } from '@/lib/supabase/auth-cookie.js';
import { beforeEach, describe, expect, it, vi } from 'vitest';

const mocks = vi.hoisted(() => ({
Expand Down Expand Up @@ -76,7 +77,7 @@ describe('public key cookie authentication', () => {
const response = await GET(
new Request('https://qrypt.chat/api/crypto/public-keys?user_id=target-user-id', {
headers: {
cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${cookieValue('access-token')};session=ignored`
cookie: `${supabaseAuthCookieName()}=${cookieValue('access-token')};session=ignored`
}
})
);
Expand All @@ -92,7 +93,7 @@ describe('public key cookie authentication', () => {
const response = await GET(
new Request('https://qrypt.chat/api/crypto/public-keys?user_id=target-user-id', {
headers: {
cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${paddedCookieValue()}`
cookie: `${supabaseAuthCookieName()}=${paddedCookieValue()}`
}
})
);
Expand All @@ -107,7 +108,7 @@ describe('public key cookie authentication', () => {
new Request('https://qrypt.chat/api/crypto/public-keys', {
method: 'PUT',
headers: {
cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${cookieValue('access-token')}`,
cookie: `${supabaseAuthCookieName()}=${cookieValue('access-token')}`,
'content-type': 'application/json'
},
body: JSON.stringify({
Expand All @@ -128,7 +129,7 @@ describe('public key cookie authentication', () => {
new Request('https://qrypt.chat/api/crypto/public-keys', {
method: 'POST',
headers: {
cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${cookieValue('access-token')}`,
cookie: `${supabaseAuthCookieName()}=${cookieValue('access-token')}`,
'content-type': 'application/json'
},
body: JSON.stringify({
Expand All @@ -147,7 +148,7 @@ describe('public key cookie authentication', () => {
it('rejects malformed and invalid public key batches', async () => {
const { POST } = await import('./route.js');
const headers = {
cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${cookieValue('access-token')}`,
cookie: `${supabaseAuthCookieName()}=${cookieValue('access-token')}`,
'content-type': 'application/json'
};
const malformedResponse = await POST(
Expand Down Expand Up @@ -176,7 +177,7 @@ describe('public key cookie authentication', () => {
new Request('https://qrypt.chat/api/crypto/public-keys', {
method: 'POST',
headers: {
cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${cookieValue('access-token')}`,
cookie: `${supabaseAuthCookieName()}=${cookieValue('access-token')}`,
'content-type': 'application/json'
},
body: JSON.stringify({ user_ids: [' user-one ', 'user-one', 'user-two'] })
Expand Down
3 changes: 2 additions & 1 deletion src/app/api/user/nuclear-delete/route.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { supabaseAuthCookieName } from '@/lib/supabase/auth-cookie.js';
import { beforeEach, describe, expect, it, vi } from 'vitest';

const mocks = vi.hoisted(() => ({
Expand Down Expand Up @@ -102,7 +103,7 @@ describe('DELETE /api/user/nuclear-delete bearer authentication', () => {
const response = await DELETE(
deleteRequest({
authorization: 'Bearer ',
cookie: `sb-xydzwxwsbgmznthiiscl-auth-token=${cookieValue('cookie-token')}`,
cookie: `${supabaseAuthCookieName()}=${cookieValue('cookie-token')}`,
'content-type': 'application/json'
})
);
Expand Down
14 changes: 14 additions & 0 deletions src/lib/supabase/auth-cookie.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* The Supabase auth cookie is named after the project URL's first host label
* (supabase-js: `sb-${hostname.split('.')[0]}-auth-token`), so it changes when
* the project moves, e.g. from <ref>.supabase.co to supabase.qrypt.chat.
* Derive it from NEXT_PUBLIC_SUPABASE_URL; never hard-code it.
*/
export function supabaseAuthCookieName(url = process.env.NEXT_PUBLIC_SUPABASE_URL) {
try {
if (url) return `sb-${new URL(url).hostname.split('.')[0]}-auth-token`;
} catch {
// fall through: an unparsable URL gets the generic name
}
return 'sb-auth-token';
}
Loading