Skip to content

Commit eecec77

Browse files
committed
feat: enhance PocketID authentication by adding custom claim check and improving email validation
1 parent 1fdb7c5 commit eecec77

File tree

2 files changed

+47
-54
lines changed

2 files changed

+47
-54
lines changed

src/modules/auth/auth.service.ts

Lines changed: 30 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import { GetStatusResponseModel } from './model/get-status.response.model';
5050
import { ILogin, IRegister } from './interfaces';
5151

5252
const scryptAsync = promisify(scrypt);
53+
const REMNAWAVE_CUSTOM_CLAIM_KEY = 'remnawaveAccess';
5354

5455
@Injectable()
5556
export class AuthService {
@@ -447,7 +448,7 @@ export class AuthService {
447448
authorizationURL = pocketIdClient.createAuthorizationURL(
448449
`https://${remnawaveSettings.oauth2Settings.pocketid.plainDomain}/authorize`,
449450
state,
450-
['email'],
451+
['email', 'profile'],
451452
);
452453
stateKey = `oauth2:${OAUTH2_PROVIDERS.POCKETID}`;
453454
break;
@@ -727,10 +728,7 @@ export class AuthService {
727728
userAgent,
728729
'PocketID OAuth2 state mismatch.',
729730
);
730-
return {
731-
isAllowed: false,
732-
email: null,
733-
};
731+
return { isAllowed: false, email: null };
734732
}
735733

736734
const remnawaveSettings = await this.queryBus.execute(
@@ -749,63 +747,43 @@ export class AuthService {
749747
null,
750748
);
751749

752-
const accessToken = tokens.accessToken();
753-
754-
const { data } = await firstValueFrom(
755-
this.httpService
756-
.get<{
757-
email: string;
758-
email_verified: boolean;
759-
sub: string;
760-
}>(
761-
`https://${remnawaveSettings.oauth2Settings.pocketid.plainDomain}/api/oidc/userinfo`,
762-
{
763-
headers: {
764-
Authorization: `Bearer ${accessToken}`,
765-
'User-Agent': 'Remnawave',
766-
},
767-
},
768-
)
769-
.pipe(
770-
catchError((error: AxiosError) => {
771-
throw error.response?.data;
772-
}),
773-
),
774-
);
750+
const claims = arctic.decodeIdToken(tokens.idToken());
775751

776-
if (!data) {
777-
this.logger.error('Failed to fetch PocketID user info');
778-
return {
779-
isAllowed: false,
780-
email: null,
781-
};
782-
}
783-
784-
if (!remnawaveSettings.oauth2Settings.pocketid.allowedEmails.includes(data.email)) {
752+
const email = 'email' in claims ? claims.email : undefined;
753+
if (typeof email !== 'string' || !email) {
785754
await this.emitFailedLoginAttempt(
786-
data.email,
755+
'Missing',
787756
'–',
788757
ip,
789758
userAgent,
790-
'PocketID email is not in the allowed list.',
759+
'Invalid or missing email claim in PocketID ID token.',
791760
);
792-
return {
793-
isAllowed: false,
794-
email: null,
795-
};
761+
return { isAllowed: false, email: null };
796762
}
797763

798-
return {
799-
isAllowed: true,
800-
email: data.email,
801-
};
764+
if (
765+
REMNAWAVE_CUSTOM_CLAIM_KEY in claims &&
766+
claims[REMNAWAVE_CUSTOM_CLAIM_KEY] === true
767+
) {
768+
return { isAllowed: true, email };
769+
}
770+
771+
if (remnawaveSettings.oauth2Settings.pocketid.allowedEmails.includes(email)) {
772+
return { isAllowed: true, email };
773+
}
774+
775+
await this.emitFailedLoginAttempt(
776+
email,
777+
'–',
778+
ip,
779+
userAgent,
780+
'PocketID email is not in the allowed list and remnawaveClaim is not present.',
781+
);
782+
783+
return { isAllowed: false, email: null };
802784
} catch (error) {
803785
this.logger.error(`PocketID callback error: ${error}`);
804-
805-
return {
806-
isAllowed: false,
807-
email: null,
808-
};
786+
return { isAllowed: false, email: null };
809787
}
810788
}
811789

src/modules/remnawave-settings/remnawave-settings.service.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,11 @@ export class RemnawaveSettingsService {
7474
try {
7575
const oauth2Providers = [
7676
settings.oauth2Settings.github,
77-
settings.oauth2Settings.pocketid,
7877
settings.oauth2Settings.yandex,
7978
];
8079

80+
const genericOAuth2Providers = [settings.oauth2Settings.pocketid];
81+
8182
// Test 1: At least one authentication method must be enabled
8283
if (
8384
!settings.passkeySettings.enabled &&
@@ -166,7 +167,21 @@ export class RemnawaveSettingsService {
166167
}
167168
}
168169

169-
// Test 8: Telegram Admin IDs must be not empty
170+
// Test 8: Other OAuth2 providers with empty allowed emails array
171+
for (const provider of genericOAuth2Providers) {
172+
if (provider.enabled && provider.allowedEmails.length > 0) {
173+
for (const email of provider.allowedEmails) {
174+
if (!isEmail(email)) {
175+
return {
176+
valid: false,
177+
error: `[OAuth2] Email ${email} is not a valid email address.`,
178+
};
179+
}
180+
}
181+
}
182+
}
183+
184+
// Test 9: Telegram Admin IDs must be not empty
170185
if (settings.tgAuthSettings.enabled && settings.tgAuthSettings.adminIds.length === 0) {
171186
return {
172187
valid: false,

0 commit comments

Comments
 (0)