Skip to content

Commit 68360b0

Browse files
committed
Merge remote-tracking branch 'origin/main' into feat/pay
2 parents dee8fd2 + ae9357d commit 68360b0

27 files changed

+1172
-206
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "omniboxd",
3-
"version": "0.1.4",
3+
"version": "0.1.10",
44
"private": true,
55
"scripts": {
66
"build": "nest build",

src/auth/auth.controller.ts

Lines changed: 78 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Response } from 'express';
22
import { AuthService } from 'omniboxd/auth/auth.service';
33
import { LocalAuthGuard } from 'omniboxd/auth/local-auth.guard';
44
import { Public } from 'omniboxd/auth/decorators/public.auth.decorator';
5+
import { UserId } from 'omniboxd/decorators/user-id.decorator';
56
import { ConfigService } from '@nestjs/config';
67
import {
78
Res,
@@ -11,9 +12,15 @@ import {
1112
UseGuards,
1213
Controller,
1314
HttpCode,
15+
Query,
1416
} from '@nestjs/common';
1517
import { ResourcePermission } from 'omniboxd/permissions/resource-permission.enum';
1618
import { NamespaceRole } from 'omniboxd/namespaces/entities/namespace-member.entity';
19+
import {
20+
SendEmailOtpDto,
21+
VerifyEmailOtpDto,
22+
SendEmailOtpResponseDto,
23+
} from './dto/email-otp.dto';
1724

1825
@Controller('api/v1')
1926
export class AuthController {
@@ -45,60 +52,77 @@ export class AuthController {
4552
}
4653

4754
@Public()
48-
@Post('sign-up')
49-
async signUp(@Body('url') url: string, @Body('email') email: string) {
50-
return await this.authService.signUp(url, email);
55+
@Post('auth/send-otp')
56+
@HttpCode(200)
57+
async sendEmailOtp(
58+
@Body() dto: SendEmailOtpDto,
59+
@Body('url') url: string,
60+
): Promise<SendEmailOtpResponseDto> {
61+
return await this.authService.sendOTP(dto.email, url);
62+
}
63+
64+
@Public()
65+
@Post('auth/send-signup-otp')
66+
@HttpCode(200)
67+
async sendSignupOtp(
68+
@Body() dto: SendEmailOtpDto,
69+
@Body('url') url: string,
70+
): Promise<SendEmailOtpResponseDto> {
71+
return await this.authService.sendSignupOTP(dto.email, url);
5172
}
5273

5374
@Public()
54-
@Post('sign-up/confirm')
55-
async signUpConfirm(
56-
@Body('token') token: string,
57-
@Body('username') username: string,
58-
@Body('password') password: string,
75+
@Post('auth/verify-otp')
76+
@HttpCode(200)
77+
async verifyEmailOtp(
78+
@Body() dto: VerifyEmailOtpDto,
5979
@Res() res: Response,
6080
@Body('lang') lang?: string,
6181
) {
62-
const signUpData = await this.authService.signUpConfirm(token, {
63-
username,
64-
password,
82+
const authData = await this.authService.verifyOTP(
83+
dto.email,
84+
dto.code,
6585
lang,
66-
});
86+
);
6787

6888
const jwtExpireSeconds = parseInt(
6989
this.configService.get('OBB_JWT_EXPIRE', '2678400'),
7090
10,
7191
);
72-
res.cookie('token', signUpData.access_token, {
92+
res.cookie('token', authData.access_token, {
7393
httpOnly: true,
7494
secure: true,
7595
sameSite: 'none',
7696
path: '/',
7797
maxAge: jwtExpireSeconds * 1000,
7898
});
7999

80-
return res.json(signUpData);
81-
}
82-
83-
@Public()
84-
@Post('password')
85-
async password(@Body('url') url: string, @Body('email') email: string) {
86-
return await this.authService.password(url, email);
100+
return res.json(authData);
87101
}
88102

89103
@Public()
90-
@Post('password/confirm')
91-
async resetPassword(
92-
@Body('token') token: string,
93-
@Body('password') password: string,
104+
@Post('auth/verify-magic')
105+
@HttpCode(200)
106+
async verifyMagicLink(
107+
@Query('token') token: string,
94108
@Res() res: Response,
109+
@Body('lang') lang?: string,
95110
) {
96-
const result = await this.authService.resetPassword(token, password);
97-
res.clearCookie('token', {
111+
const authData = await this.authService.verifyMagicLink(token, lang);
112+
113+
const jwtExpireSeconds = parseInt(
114+
this.configService.get('OBB_JWT_EXPIRE', '2678400'),
115+
10,
116+
);
117+
res.cookie('token', authData.access_token, {
98118
httpOnly: true,
119+
secure: true,
120+
sameSite: 'none',
99121
path: '/',
122+
maxAge: jwtExpireSeconds * 1000,
100123
});
101-
return res.json(result);
124+
125+
return res.json(authData);
102126
}
103127

104128
@Post('invite')
@@ -140,8 +164,33 @@ export class AuthController {
140164
}
141165

142166
@Post('invite/confirm')
143-
async inviteConfirm(@Body('token') token: string) {
144-
return await this.authService.inviteConfirm(token);
167+
async inviteConfirm(@UserId() userId: string, @Body('token') token: string) {
168+
return await this.authService.inviteConfirm(token, userId);
169+
}
170+
171+
@Public()
172+
@Post('auth/accept-invite')
173+
@HttpCode(200)
174+
async acceptInvite(
175+
@Query('token') token: string,
176+
@Res() res: Response,
177+
@Body('lang') lang?: string,
178+
) {
179+
const authData = await this.authService.acceptInvite(token, lang);
180+
181+
const jwtExpireSeconds = parseInt(
182+
this.configService.get('OBB_JWT_EXPIRE', '2678400'),
183+
10,
184+
);
185+
res.cookie('token', authData.access_token, {
186+
httpOnly: true,
187+
secure: true,
188+
sameSite: 'none',
189+
path: '/',
190+
maxAge: jwtExpireSeconds * 1000,
191+
});
192+
193+
return res.json(authData);
145194
}
146195

147196
@Post('logout')

src/auth/auth.e2e-spec.ts

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -254,18 +254,6 @@ describe('AuthModule (e2e)', () => {
254254
});
255255
});
256256

257-
it('should access sign-up endpoint without authentication', async () => {
258-
// Note: This will fail due to email service in test environment, but endpoint should be accessible
259-
await client
260-
.request()
261-
.post('/api/v1/sign-up')
262-
.send({
263-
url: 'http://localhost:3000/signup',
264-
email: 'test-signup@example.com',
265-
})
266-
.expect(201);
267-
});
268-
269257
it('should access WeChat QR code endpoint without authentication', async () => {
270258
await client
271259
.request()
@@ -484,55 +472,4 @@ describe('AuthModule (e2e)', () => {
484472
.expect(HttpStatus.UNAUTHORIZED);
485473
});
486474
});
487-
488-
describe('Sign-up Flow', () => {
489-
describe('POST /api/v1/sign-up/confirm', () => {
490-
it('should fail with invalid token', async () => {
491-
await client
492-
.request()
493-
.post('/api/v1/sign-up/confirm')
494-
.send({
495-
token: 'invalid-token',
496-
username: 'testuser',
497-
password: 'testpassword',
498-
})
499-
.expect(HttpStatus.UNAUTHORIZED);
500-
});
501-
502-
it('should fail with missing parameters', async () => {
503-
await client
504-
.request()
505-
.post('/api/v1/sign-up/confirm')
506-
.send({
507-
token: 'some-token',
508-
// Missing username and password
509-
})
510-
.expect(HttpStatus.UNAUTHORIZED); // Invalid token gets processed first
511-
});
512-
});
513-
514-
describe('POST /api/v1/password', () => {
515-
it('should initiate password reset for existing user', async () => {
516-
await client
517-
.request()
518-
.post('/api/v1/password')
519-
.send({
520-
url: 'http://localhost:3000/reset-password',
521-
email: client.user.email,
522-
})
523-
.expect(201);
524-
});
525-
526-
it('should fail for non-existent user', async () => {
527-
await client
528-
.request()
529-
.post('/api/v1/password')
530-
.send({
531-
url: 'http://localhost:3000/reset-password',
532-
email: 'nonexistent@example.com',
533-
})
534-
.expect(HttpStatus.NOT_FOUND);
535-
});
536-
});
537-
});
538475
});

src/auth/auth.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { WechatController } from 'omniboxd/auth/wechat/wechat.controller';
2020
import { GoogleService } from 'omniboxd/auth/google/google.service';
2121
import { GoogleController } from 'omniboxd/auth/google/google.controller';
2222
import { SocialService } from 'omniboxd/auth/social.service';
23+
import { OtpService } from 'omniboxd/auth/otp.service';
2324
import { APIKeyModule } from 'omniboxd/api-key/api-key.module';
2425
import { APIKeyAuthGuard } from 'omniboxd/auth/api-key/api-key-auth.guard';
2526
import { CookieAuthGuard } from 'omniboxd/auth/cookie/cookie-auth.guard';
@@ -36,6 +37,7 @@ import { CacheService } from 'omniboxd/common/cache.service';
3637
providers: [
3738
AuthService,
3839
SocialService,
40+
OtpService,
3941
WechatService,
4042
GoogleService,
4143
JwtStrategy,

0 commit comments

Comments
 (0)