Skip to content

Commit

Permalink
Fix profile session location
Browse files Browse the repository at this point in the history
For user profiles where active sessions are shown, our local location service was not handled correctly where the shape of the data had a wrapper object that was not included from ip-api

Added graceful shutdown handling for jetstream core api server
  • Loading branch information
paustint committed Jan 1, 2025
1 parent 020409c commit 5937d87
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 22 deletions.
18 changes: 18 additions & 0 deletions apps/api/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,24 @@ if (ENV.NODE_ENV === 'production' && !ENV.CI && cluster.isPrimary) {
server.on('error', (error: Error) => {
logger.error(getExceptionLog(error), '[SERVER][ERROR]');
});

process.on('SIGTERM', () => {
logger.info('SIGTERM received, shutting down gracefully');
server.close(() => {
logger.info('Server closed');

pgPool.end().then(() => {
logger.info('DB pool closed');
process.exit(0);
});
});

// Force close after 30s
setTimeout(() => {
logger.error('Could not close connections in time, forcefully shutting down');
process.exit(1);
}, 30_000);
});
}

/**
Expand Down
12 changes: 7 additions & 5 deletions apps/geo-ip-api/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,10 @@ app.use('*', (req, res, next) => {
});

app.use((err: Error | ZodError, req: express.Request, res: express.Response, next: express.NextFunction) => {
res.log.error('Unhandled error:', err);

if (!res.statusCode) {
res.status(500);
}
res.log.error({ ...getExceptionLog(err) }, 'Unhandled error');

if (err instanceof ZodError) {
res.status(400);
res.json({
success: false,
message: 'Validation error',
Expand All @@ -142,6 +139,10 @@ app.use((err: Error | ZodError, req: express.Request, res: express.Response, nex
return;
}

if (!res.statusCode || res.statusCode < 400) {
res.status(500);
}

res.json({
success: false,
message: err.message,
Expand All @@ -153,6 +154,7 @@ const port = Number(process.env.PORT || 3334);
const server = app.listen(port, () => {
logger.info(`Listening at http://localhost:${port}/api`);
});

server.on('error', (error) => {
logger.error(getExceptionLog(error, true), 'Server error: %s', error.message);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const Profile2fa: FunctionComponent<Profile2faProps> = ({ authFactors, on
`}
>
{!has2faEnabled && (
<ScopedNotification theme="warning" className="slds-m-vertical_medium">
<ScopedNotification theme="warning" className="slds-m-around_medium">
You don't have two-factor authentication enabled. Enable it to add an extra layer of security to your account.
</ScopedNotification>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,21 @@ function Location({ location }: { location: SessionIpData }) {
if (location.status !== 'success') {
return null;
}
const { city, countryCode } = location;
return (
<span>
({city}, {countryCode})
</span>
);
const { city, region, countryCode, lat, lon } = location;

const estimatedLocation = [city, region, countryCode].filter(Boolean).join(', ');

if (lat && lon) {
return (
<span>
(Est. location:{' '}
<a href={`https://www.google.com/maps?q=${lat},${lon}`} target="_blank" rel="noopener noreferrer">
{estimatedLocation}
</a>
)
</span>
);
}

return <span>(Est. location: {estimatedLocation})</span>;
}
34 changes: 24 additions & 10 deletions libs/auth/server/src/lib/auth.db.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,25 +296,39 @@ export async function getUserSessions(userId: string, omitLocationData?: boolean
},
body: JSON.stringify({ ips: ipAddresses }),
});
if (response?.ok) {
const locations = (await response.json()) as
| { success: true; results: SessionIpData[] }
| { success: false; message: string; details?: string };

if (locations.success) {
return sessions.map(
(session, i): UserSessionWithLocation => ({
...session,
location: locations.results[i],
})
);
}
}
} else if (ENV.IP_API_KEY) {
const params = new URLSearchParams({
fields: 'status,country,countryCode,region,regionName,city,isp,query',
fields: 'status,country,countryCode,region,regionName,city,isp,lat,lon,query',
key: ENV.IP_API_KEY,
});

response = await fetch(`https://pro.ip-api.com/batch?${params.toString()}`, {
method: 'POST',
body: JSON.stringify(ipAddresses),
});
}
if (response?.ok) {
const locations = (await response.json()) as SessionIpData[];
return sessions.map(
(session, i): UserSessionWithLocation => ({
...session,
location: locations[i],
})
);
if (response?.ok) {
const locations = (await response.json()) as SessionIpData[];
return sessions.map(
(session, i): UserSessionWithLocation => ({
...session,
location: locations[i],
})
);
}
}
} catch (ex) {
logger.warn({ ...getErrorMessageAndStackObj(ex) }, 'Error fetching location data for sessions');
Expand Down
2 changes: 2 additions & 0 deletions libs/auth/types/src/lib/auth-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ export interface SessionIpSuccess {
regionName: string | null;
city: string | null;
isp: string | null;
lat: number | null;
lon: number | null;
query: string | null;
}

Expand Down

0 comments on commit 5937d87

Please sign in to comment.