Skip to content
Open
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,6 @@ certificates
.sfdx/
**/.sf/
**/.sfdx/

.nx/polygraph
.nx/self-healing
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@
/.nx/cache
/.nx/workspace-data
**/monaco/vs/

.nx/self-healing
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ const authServerMocks = vi.hoisted(() => {
generatePasswordResetToken: vi.fn(),
generateRandomCode: vi.fn(() => '123456'),
generateRandomString: vi.fn(() => 'random-string'),
getApiAddressFromReq: vi.fn(() => '127.0.0.1'),
getAuthorizationUrl: vi.fn(),
getCookieConfig: vi.fn(() => ({
csrfToken: { name: 'csrfToken', options: {} },
Expand Down Expand Up @@ -166,6 +165,7 @@ type MockRequest = {
get: (name: string) => string | undefined;
log: { info: ReturnType<typeof vi.fn>; warn: ReturnType<typeof vi.fn>; error: ReturnType<typeof vi.fn>; debug: ReturnType<typeof vi.fn> };
ip: string;
ipAddress: string;
};

function makeReq(overrides: Partial<MockRequest> = {}): MockRequest {
Expand All @@ -183,13 +183,14 @@ function makeReq(overrides: Partial<MockRequest> = {}): MockRequest {
get: vi.fn(() => undefined),
log: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
ip: '127.0.0.1',
ipAddress: '127.0.0.1',
...overrides,
};
}

function makeRes() {
const res = {
locals: { cookies: {}, requestId: 'request-id', ipAddress: '127.0.0.1' },
locals: { cookies: {}, requestId: 'request-id' },
log: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
json: vi.fn(),
status: vi.fn(),
Expand Down Expand Up @@ -226,7 +227,6 @@ describe('auth.controller - placeholder session email suppression', () => {
} as never);
authServerMocks.generateRandomCode.mockReturnValue('123456');
authServerMocks.ensureAuthError.mockImplementation((error: unknown) => error);
authServerMocks.getApiAddressFromReq.mockReturnValue('127.0.0.1');
authServerMocks.validateRedirectUrl.mockImplementation((url: string) => url || 'https://client.test');
emailMocks.sendEmailVerification.mockResolvedValue(undefined);
emailMocks.sendVerificationCode.mockResolvedValue(undefined);
Expand Down Expand Up @@ -558,7 +558,6 @@ describe('auth.controller - SSO callback redirect resolution', () => {
} as never);
authServerMocks.ensureAuthError.mockImplementation((error: unknown) => error);
authServerMocks.validateRedirectUrl.mockImplementation((url: string) => url || 'https://client.test');
authServerMocks.getApiAddressFromReq.mockReturnValue('127.0.0.1');
authServerMocks.handleSsoLogin.mockResolvedValue({ id: 'sso-user-id', email: 'sso@example.com' } as never);
authServerMocks.getTeamLoginConfigWithSso.mockResolvedValue({
loginConfig: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ const authServerMocks = vi.hoisted(() => {
generate2faTotpUrl: vi.fn(),
generatePasswordResetToken: vi.fn(),
getAllSessions: vi.fn(),
getApiAddressFromReq: vi.fn(() => '127.0.0.1'),
getAuthorizationUrl: vi.fn(),
getCookieConfig: vi.fn(() => ({})),
getLoginConfiguration: vi.fn(),
Expand Down Expand Up @@ -116,6 +115,7 @@ type MockRequest = {
get: (name: string) => string | undefined;
log: { info: ReturnType<typeof vi.fn>; warn: ReturnType<typeof vi.fn>; error: ReturnType<typeof vi.fn>; debug: ReturnType<typeof vi.fn> };
ip: string;
ipAddress: string;
};

function makeReq(overrides: Partial<MockRequest> = {}): MockRequest {
Expand All @@ -134,13 +134,14 @@ function makeReq(overrides: Partial<MockRequest> = {}): MockRequest {
get: vi.fn(() => undefined),
log: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
ip: '127.0.0.1',
ipAddress: '127.0.0.1',
...overrides,
};
}

function makeRes() {
const res = {
locals: { cookies: {}, requestId: 'request-id', ipAddress: '127.0.0.1' },
locals: { cookies: {}, requestId: 'request-id' },
log: { info: vi.fn(), warn: vi.fn(), error: vi.fn(), debug: vi.fn() },
json: vi.fn(),
status: vi.fn(),
Expand Down
5 changes: 2 additions & 3 deletions apps/api/src/app/controllers/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
generatePasswordResetToken,
generateRandomCode,
generateRandomString,
getApiAddressFromReq,
getAuthorizationUrl,
getCookieConfig,
getLoginConfiguration,
Expand Down Expand Up @@ -618,7 +617,7 @@ const callback = createRoute(
const isDeviceRemembered = await hasRememberDeviceRecord({
userId: req.session.user.id,
deviceId,
ipAddress: res.locals.ipAddress || getApiAddressFromReq(req),
ipAddress: req.ipAddress,
userAgent: req.get('User-Agent'),
});
if (isDeviceRemembered) {
Expand Down Expand Up @@ -828,7 +827,7 @@ const verification = createRoute(
await createRememberDevice({
userId: user.id,
deviceId: rememberDeviceId,
ipAddress: res.locals.ipAddress || getApiAddressFromReq(req),
ipAddress: req.ipAddress,
userAgent: req.get('User-Agent'),
});
setCookie(cookieConfig.rememberDevice.name, rememberDeviceId, cookieConfig.rememberDevice.options);
Expand Down
12 changes: 3 additions & 9 deletions apps/api/src/app/controllers/desktop-app.controller.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import { ENV } from '@jetstream/api-config';
import {
createUserActivityFromReq,
getApiAddressFromReq,
getCookieConfig,
InvalidSession,
MissingEntitlement,
} from '@jetstream/auth/server';
import { createUserActivityFromReq, getCookieConfig, InvalidSession, MissingEntitlement } from '@jetstream/auth/server';
import { NotificationMessageV1Response } from '@jetstream/desktop/types';
import { HTTP } from '@jetstream/shared/constants';
import { getErrorMessageAndStackObj } from '@jetstream/shared/utils';
Expand Down Expand Up @@ -183,7 +177,7 @@ const initSession = createRoute(routeDefinition.initSession.validators, async ({
source: webExtDb.TOKEN_SOURCE_DESKTOP,
token: accessToken,
deviceId,
ipAddress: res.locals.ipAddress || getApiAddressFromReq(req),
ipAddress: req.ipAddress,
userAgent: req.get('User-Agent') || 'unknown',
expiresAt: fromUnixTime(externalAuthService.decodeToken(accessToken).exp),
provider: req.session.provider,
Expand Down Expand Up @@ -226,7 +220,7 @@ const verifyToken = createRoute(routeDefinition.verifyToken.validators, async ({
source: webExtDb.TOKEN_SOURCE_DESKTOP,
deviceId,
oldAccessToken,
ipAddress: res.locals.ipAddress || getApiAddressFromReq(req),
ipAddress: req.ipAddress,
userAgent: req.get('User-Agent') || 'unknown',
});
if (rotatedAccessToken) {
Expand Down
38 changes: 19 additions & 19 deletions apps/api/src/app/controllers/team.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ const acceptInvitation = createRoute(routeDefinition.acceptInvitation.validators
resource: AuditLogResource.TEAM_MEMBER,
resourceId: user.id,
metadata: { inviteeEmail, role, features },
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
});
Expand All @@ -519,7 +519,7 @@ const updateTeam = createRoute(routeDefinition.updateTeam.validators, async ({ p
resource: AuditLogResource.TEAM,
resourceId: teamId,
metadata: { previousName: previousTeam.name, newName: team.name },
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
});
Expand Down Expand Up @@ -547,7 +547,7 @@ const revokeUserSession = createRoute(routeDefinition.revokeUserSession.validato
resource: AuditLogResource.TEAM_MEMBER,
resourceId: targetUserId,
metadata: { targetUserId, sessionId },
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
}
Expand Down Expand Up @@ -599,7 +599,7 @@ const updateLoginConfiguration = createRoute(
resource: AuditLogResource.TEAM_LOGIN_CONFIG,
resourceId: team.loginConfigId ?? undefined,
metadata: { changes, sessionsRevoked },
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
},
Expand Down Expand Up @@ -639,7 +639,7 @@ const updateTeamMember = createRoute(routeDefinition.updateTeamMember.validators
previousFeatures: previousMember.features,
newFeatures: updatedMember?.features ?? body.features,
},
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
});
Expand Down Expand Up @@ -683,7 +683,7 @@ const updateTeamMemberStatusAndRole = createRoute(
newRole: updatedMember?.role ?? role ?? previousMember.role,
allSessionsRevoked,
},
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
},
Expand Down Expand Up @@ -725,7 +725,7 @@ const createInvitation = createRoute(routeDefinition.createInvitation.validators
features: createdInvitation.features,
expiresAt: createdInvitation.expiresAt.toISOString(),
},
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
});
Expand Down Expand Up @@ -764,7 +764,7 @@ const resendInvitation = createRoute(routeDefinition.resendInvitation.validators
resource: AuditLogResource.TEAM_INVITATION,
resourceId: updatedInvitation.id,
metadata: { inviteeEmail: updatedInvitation.email, role: updatedInvitation.role },
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
});
Expand Down Expand Up @@ -792,7 +792,7 @@ const cancelInvitation = createRoute(routeDefinition.cancelInvitation.validators
resource: AuditLogResource.TEAM_INVITATION,
resourceId: id,
metadata: { inviteeEmail: existingInvitation.email, role: existingInvitation.role },
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
});
Expand Down Expand Up @@ -880,7 +880,7 @@ const createOrUpdateSamlConfig = createRoute(
// nameIdFormat: configData.nameIdFormat,
// wantAssertionsSigned: configData.wantAssertionsSigned,
},
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
} else if (previousSamlConfig) {
Expand Down Expand Up @@ -919,7 +919,7 @@ const createOrUpdateSamlConfig = createRoute(
resource: AuditLogResource.TEAM_SSO_CONFIG,
resourceId: previousSamlConfig.id,
metadata: { provider: 'SAML', configId: previousSamlConfig.id, changes },
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
}
Expand Down Expand Up @@ -997,7 +997,7 @@ const createOrUpdateOidcConfig = createRoute(
scopes: body.scopes,
attributeMapping: body.attributeMapping,
},
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
} else if (previousOidcConfig) {
Expand All @@ -1021,7 +1021,7 @@ const createOrUpdateOidcConfig = createRoute(
resource: AuditLogResource.TEAM_SSO_CONFIG,
resourceId: previousOidcConfig.id,
metadata: { provider: 'OIDC', configId: previousOidcConfig.id, changes },
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
}
Expand Down Expand Up @@ -1055,7 +1055,7 @@ const updateSsoSettings = createRoute(routeDefinition.updateSsoSettings.validato
resource: AuditLogResource.TEAM_LOGIN_CONFIG,
resourceId: config.id,
metadata: { changes },
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
} catch (ex) {
Expand All @@ -1078,7 +1078,7 @@ const deleteSamlConfig = createRoute(routeDefinition.deleteSamlConfig.validators
resource: AuditLogResource.TEAM_SSO_CONFIG,
resourceId: deletedConfig.id,
metadata: { provider: 'SAML', idpEntityId: deletedConfig.idpEntityId, affectedIdentitiesCount },
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
}
Expand All @@ -1102,7 +1102,7 @@ const deleteOidcConfig = createRoute(routeDefinition.deleteOidcConfig.validators
resource: AuditLogResource.TEAM_SSO_CONFIG,
resourceId: deletedConfig.id,
metadata: { provider: 'OIDC', issuer: deletedConfig.issuer, clientId: deletedConfig.clientId, affectedIdentitiesCount },
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
}
Expand Down Expand Up @@ -1144,7 +1144,7 @@ const saveDomainVerification = createRoute(
resourceId: result.id,
// verificationCode intentionally excluded — it is a shared secret
metadata: { domain, status: 'PENDING' },
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
} catch (ex) {
Expand Down Expand Up @@ -1238,7 +1238,7 @@ const verifyDomain = createRoute(routeDefinition.verifyDomain.validators, async
resource: AuditLogResource.TEAM_DOMAIN_VERIFICATION,
resourceId: domainId,
metadata: { domain: verification.domain, method: verificationMethod, verifiedAt: result.verifiedAt },
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
} else {
Expand Down Expand Up @@ -1269,7 +1269,7 @@ const deleteDomainVerification = createRoute(
wasVerified: deletedRecord.status === 'VERIFIED',
previousStatus: deletedRecord.status,
},
ipAddress: req.ip,
ipAddress: req.ipAddress,
userAgent: req.headers['user-agent'] as string,
});
} catch (ex) {
Expand Down
5 changes: 1 addition & 4 deletions apps/api/src/app/controllers/user-feedback.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ENV, logger } from '@jetstream/api-config';
import { getApiAddressFromReq } from '@jetstream/auth/server';
import { HTTP } from '@jetstream/shared/constants';
import express from 'express';
import z from 'zod';
Expand All @@ -18,12 +17,10 @@ export const sendUserFeedbackEmail = async (req: express.Request, res: express.R
return res.status(401).json({ error: 'Unauthorized' });
}

const ipAddress = getApiAddressFromReq(req);

const parsedPayload = UserFeedbackPayloadSchema.safeParse({
...req.body,
deviceId: req.get(HTTP.HEADERS.X_EXT_DEVICE_ID),
ipAddress,
ipAddress: req.ipAddress,
requestId: res.locals?.requestId,
serverVersion: ENV.VERSION,
userAgent: req.headers['user-agent'],
Expand Down
12 changes: 3 additions & 9 deletions apps/api/src/app/controllers/web-extension.controller.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import { ENV } from '@jetstream/api-config';
import {
createUserActivityFromReq,
getApiAddressFromReq,
getCookieConfig,
InvalidSession,
MissingEntitlement,
} from '@jetstream/auth/server';
import { createUserActivityFromReq, getCookieConfig, InvalidSession, MissingEntitlement } from '@jetstream/auth/server';
import { HTTP } from '@jetstream/shared/constants';
import { getErrorMessageAndStackObj } from '@jetstream/shared/utils';
import { UserProfileUiSchema } from '@jetstream/types';
Expand Down Expand Up @@ -164,7 +158,7 @@ const initSession = createRoute(routeDefinition.initSession.validators, async ({
source: webExtDb.TOKEN_SOURCE_BROWSER_EXTENSION,
token: accessToken,
deviceId,
ipAddress: res.locals.ipAddress || getApiAddressFromReq(req),
ipAddress: req.ipAddress,
userAgent: req.get('User-Agent') || 'unknown',
expiresAt: fromUnixTime(externalAuthService.decodeToken(accessToken).exp),
provider: req.session.provider,
Expand Down Expand Up @@ -199,7 +193,7 @@ const verifyToken = createRoute(routeDefinition.verifyToken.validators, async ({
source: webExtDb.TOKEN_SOURCE_BROWSER_EXTENSION,
deviceId,
oldAccessToken,
ipAddress: res.locals.ipAddress || getApiAddressFromReq(req),
ipAddress: req.ipAddress,
userAgent: req.get('User-Agent') || 'unknown',
});
if (rotatedAccessToken) {
Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/app/routes/api.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
checkAuth,
ensureTargetOrgExists,
feedbackRateLimit,
feedbackUploadMiddleware,
feedbackScreenshotsUploadMiddleware,
passwordResetEmailRateLimit,
validateDoubleCSRF,
verifyEntitlement,
Expand Down Expand Up @@ -218,7 +218,7 @@ routes.get('/salesforce-api/requests', salesforceApiReqController.getSalesforceA
* User Feedback Routes
* ************************************
*/
routes.post('/feedback', feedbackRateLimit, feedbackUploadMiddleware.array('screenshots', 5), userFeedbackController.sendUserFeedbackEmail);
routes.post('/feedback', feedbackRateLimit, feedbackScreenshotsUploadMiddleware, userFeedbackController.sendUserFeedbackEmail);

/**
* ************************************
Expand Down
Loading
Loading