Skip to content

Commit bec932d

Browse files
authored
Merge pull request #1727 from mxllv/fix/issues-1563-1564-1565-1566-tracking-view-token-select-public-root-timing
fix(backend): public tracking view, hide verification token, public root route, equalise login timing
2 parents 81a3dc9 + c7257c7 commit bec932d

4 files changed

Lines changed: 44 additions & 2 deletions

File tree

‎backend/src/app.controller.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { Controller, Get } from '@nestjs/common';
22
import { AppService } from './app.service';
3+
import { Public } from './auth/decorators/public.decorator';
34

45
@Controller()
56
export class AppController {
67
constructor(private readonly appService: AppService) {}
78

9+
@Public()
810
@Get()
911
getHello(): string {
1012
return this.appService.getHello();

‎backend/src/auth/auth.service.ts‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ export interface AuthResponse {
2727
refreshToken: string;
2828
}
2929

30+
// Hash of a throwaway password, compared against when the email is unknown so
31+
// that "no such account" and "wrong password" cost the same bcrypt work.
32+
const TIMING_EQUALISATION_HASH = bcrypt.hashSync(
33+
'timing-equalisation-password',
34+
12,
35+
);
36+
3037
@Injectable()
3138
export class AuthService {
3239
private readonly logger = new Logger(AuthService.name);
@@ -41,7 +48,10 @@ export class AuthService {
4148

4249
async validateUser(email: string, password: string): Promise<User | null> {
4350
const user = await this.usersService.findByEmail(email);
44-
if (!user) return null;
51+
if (!user) {
52+
await this.usersService.verifyPassword(password, TIMING_EQUALISATION_HASH);
53+
return null;
54+
}
4555
const isMatch = await this.usersService.verifyPassword(
4656
password,
4757
user.passwordHash,

‎backend/src/shipments/shipments.service.ts‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,31 @@ export class ShipmentsService {
486486
};
487487
}
488488

489+
/**
490+
* Public tracking view: status and route only. The full shipment (price,
491+
* cargo description, notes, party records) is never returned here.
492+
*/
493+
async findByTracking(trackingNumber: string) {
494+
const shipment = await this.shipmentRepo.findOne({
495+
where: { trackingNumber },
496+
});
497+
if (!shipment) {
498+
throw new NotFoundException(
499+
`No shipment found for tracking number ${trackingNumber}`,
500+
);
501+
}
502+
return {
503+
trackingNumber: shipment.trackingNumber,
504+
status: shipment.status,
505+
origin: shipment.origin,
506+
destination: shipment.destination,
507+
pickupDate: shipment.pickupDate,
508+
estimatedDeliveryDate: shipment.estimatedDeliveryDate,
509+
actualDeliveryDate: shipment.actualDeliveryDate,
510+
updatedAt: shipment.updatedAt,
511+
};
512+
}
513+
489514
async update(
490515
id: string,
491516
shipperId: string,

‎backend/src/users/entities/user.entity.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,12 @@ export class User {
5050
})
5151
refreshToken: string | null;
5252

53-
@Column({ name: 'verification_token', nullable: true, type: 'varchar' })
53+
@Column({
54+
name: 'verification_token',
55+
nullable: true,
56+
type: 'varchar',
57+
select: false,
58+
})
5459
verificationToken: string | null;
5560

5661
@Column({

0 commit comments

Comments
 (0)