Skip to content

Commit ccf0fd0

Browse files
authored
Merge pull request #58 from GeneralMagicio/add_cors_allow_list
feat: add cors allow list and allow tunnels for testing on WLD mini app
2 parents 43b4aae + 34be9e0 commit ccf0fd0

File tree

4 files changed

+61
-8
lines changed

4 files changed

+61
-8
lines changed

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
DATABASE_URL=
2+
WHITELISTED_ORIGINS=
3+
TUNNEL_DOMAINS=

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ lerna-debug.log*
4141
.env.test.local
4242
.env.production.local
4343
.env.local
44+
!.env.example
4445

4546
# temp directory
4647
.temp

src/auth/auth.controller.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,24 @@ import { MiniAppWalletAuthSuccessPayload } from '@worldcoin/minikit-js';
66
interface IRequestPayload {
77
payload: MiniAppWalletAuthSuccessPayload;
88
}
9+
10+
function isHttps(req: Request) {
11+
return (
12+
req.protocol === 'https' || req.headers['x-forwarded-proto'] === 'https'
13+
);
14+
}
15+
916
@Controller('auth')
1017
export class AuthController {
1118
constructor(private readonly authService: AuthService) {}
1219

1320
@Get('nonce')
14-
async generateNonce(@Res() res: Response): Promise<any> {
21+
generateNonce(@Req() req: Request, @Res() res: Response) {
1522
const nonce = this.authService.generateNonce();
1623
res.cookie('siwe', nonce, {
1724
httpOnly: true,
18-
secure: process.env.NODE_ENV === 'production',
19-
sameSite: 'strict',
25+
secure: process.env.NODE_ENV === 'production' || isHttps(req),
26+
sameSite: 'none',
2027
maxAge: 2 * 60 * 1000, //2 minutes
2128
});
2229

@@ -45,6 +52,7 @@ export class AuthController {
4552
);
4653
return res.status(200).json({ isValid: validMessage });
4754
} catch (error: any) {
55+
console.log('Error verifying payload:', error);
4856
return res
4957
.status(400)
5058
.json({ status: 'error', isValid: false, message: error.message });

src/main.ts

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,54 @@ import { ValidationPipe } from '@nestjs/common';
66
async function bootstrap() {
77
const app = await NestFactory.create(AppModule);
88

9-
app.useGlobalPipes(
10-
new ValidationPipe({
11-
transform: true,
12-
}),
13-
);
9+
const environment = process.env.NODE_ENV || 'development';
10+
const rawOrigins = process.env.WHITELISTED_ORIGINS || '';
11+
const rawTunnelDomains = process.env.TUNNEL_DOMAINS || '';
12+
13+
const whiteListedOrigins = rawOrigins
14+
.split(',')
15+
.map((origin) => origin.trim().replace(/^https?:\/\//, ''))
16+
.filter((origin) => !!origin);
17+
18+
const tunnelDomains = rawTunnelDomains
19+
.split(',')
20+
.map((domain) => domain.trim())
21+
.filter((domain) => !!domain);
22+
23+
app.enableCors({
24+
origin: (
25+
origin: string | undefined,
26+
callback: (err: Error | null, allow?: boolean) => void,
27+
) => {
28+
if (!origin) return callback(null, true);
29+
30+
try {
31+
const { hostname } = new URL(origin);
32+
33+
const isWhitelisted = whiteListedOrigins.includes(hostname);
34+
35+
const isTunnelDomain =
36+
environment !== 'production' &&
37+
tunnelDomains.some((testDomain) => hostname.endsWith(testDomain));
38+
39+
if (isWhitelisted || isTunnelDomain) {
40+
return callback(null, true);
41+
}
42+
43+
console.error(`[CORS ERROR]: Origin ${origin} is not allowed.`);
44+
return callback(new Error(`CORS blocked for origin: ${origin}`));
45+
} catch (error) {
46+
console.error(`[CORS ERROR]: Malformed origin`, error);
47+
return callback(new Error(`Invalid origin: ${origin}`));
48+
}
49+
},
50+
credentials: true,
51+
});
52+
53+
app.useGlobalPipes(new ValidationPipe({ transform: true }));
1454
app.use(cookieParser());
1555

1656
await app.listen(process.env.PORT ?? 3000);
1757
}
58+
1859
bootstrap();

0 commit comments

Comments
 (0)