Skip to content

Commit a02fb92

Browse files
committed
Update experience to add Booking.com
1 parent b091abd commit a02fb92

4 files changed

Lines changed: 60 additions & 12 deletions

File tree

public/static/booking-logo.jpg

6.24 KB
Loading

src/data.json

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,34 @@
1515
"github": "https://github.com/chapmankyle"
1616
},
1717
"experience": [
18+
{
19+
"id": 7,
20+
"dateAsString": "2025-07-01",
21+
"startDate": "Jul 2025",
22+
"endDate": "present",
23+
"title": "Full Stack Software Engineer I",
24+
"type": "Full-time",
25+
"company": "Booking.com B.V.",
26+
"imagePath": "/static/booking-logo.jpg",
27+
"technologies": ["TypeScript", "Node.js", "React", "Java", "Spring Boot", "Perl"],
28+
"location": {
29+
"flag": "🇳🇱",
30+
"name": "Amsterdam, Netherlands"
31+
}
32+
},
1833
{
1934
"id": 6,
20-
"dateAsString": "2024-04-01",
2135
"startDate": "Apr 2024",
22-
"endDate": "present",
36+
"endDate": "Jun 2025",
37+
"duration": {
38+
"years": 1,
39+
"months": 3
40+
},
2341
"title": "Full Stack Engineer",
2442
"type": "Full-time",
2543
"company": "Zilverline B.V.",
2644
"imagePath": "/static/zilverline-logo.jpg",
27-
"description": "I am part of a team that is developing a **multi-tenant, e-commerce platform** that facilitates buying products from a **range of shops**. Supports **various payment methods** (iDEAL, Klarna, etc.) product returns, order tracking (DHL & PostNL), promotions, coupon codes, and more.\n\nSome of my responsibilities are:\n- **Development**: 50% frontend / 40% backend / 10% maintenance\n- **Shop onboarding overhaul** to increase the number of shops onboarded\n- Dashboard **UI/UX** updates to make it easier for shop owners to find the information they need\n- **Prompt engineering** using OpenAI models to **automatically generate** product descriptions, about pages and more\n- **Production** deployments\n- Performing **code reviews**",
45+
"description": "I was part of a team that was developing a **multi-tenant, e-commerce platform** that facilitated buying products from a **range of shops**. It supported **various payment methods** (iDEAL, Klarna, etc.) product returns, order tracking (DHL & PostNL), promotions, coupon codes, and more.\n\nSome of my responsibilities were:\n- **Development**: 50% frontend / 40% backend / 10% maintenance\n- **Shop onboarding overhaul** to increase the number of shops onboarded\n- Dashboard **UI/UX** updates to make it easier for shop owners to find the information they need\n- **Prompt engineering** using OpenAI models to **automatically generate** product descriptions, about pages and more\n- **Production** deployments\n- Performing **code reviews**",
2846
"technologies": ["Ruby on Rails", "JavaScript", "Stimulus", "Bootstrap", "Node.js", "PostgreSQL", "GitHub Actions"],
2947
"location": {
3048
"flag": "🇳🇱",

src/index.ts

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@ app.use(prettyJSON())
2626
// Only allow requests from my domain
2727
app.use('/*', cors({
2828
origin: (origin, c) => {
29-
return origin.endsWith(ALLOWED_HOST)
30-
? origin
31-
: `https://${ALLOWED_HOST}`
29+
// Exact match for the domain or www subdomain only
30+
const allowedOrigins = [`https://${ALLOWED_HOST}`, `https://www.${ALLOWED_HOST}`]
31+
return allowedOrigins.includes(origin) ? origin : `https://${ALLOWED_HOST}`
3232
},
33-
allowMethods: ['GET', 'POST']
33+
allowMethods: ['GET', 'POST'],
34+
allowHeaders: ['Authorization', 'Content-Type'],
35+
exposeHeaders: ['Content-Length'],
36+
maxAge: 3600
3437
}))
3538

3639
// CSRF protection
@@ -55,23 +58,47 @@ app.post('/authorize', async (c) => {
5558
iat: now
5659
}
5760

61+
// Create refresh token with longer expiration
62+
const refreshPayload = {
63+
role: 'refresh',
64+
exp: now + 3600, // Refresh token expires in 1 hour
65+
iat: now
66+
}
67+
5868
const token = await sign(payload, c.env.JWT_SECRET)
69+
const refreshToken = await sign(refreshPayload, c.env.JWT_SECRET)
70+
5971
return c.json({
6072
payload,
61-
token
73+
token,
74+
refreshToken
6275
})
6376
})
6477

6578
// Route with new API
6679
app.use('/v2/*', bearerAuth({
6780
verifyToken: async (token, c) => {
6881
try {
69-
await verify(token, c.env.JWT_SECRET)
82+
const payload = await verify(token, c.env.JWT_SECRET)
83+
84+
// Check if token is expired by checking current time against exp
85+
const now = Math.floor(Date.now() / 1000)
86+
if (payload.exp && payload.exp < now) {
87+
console.error('Token expired')
88+
return false
89+
}
90+
91+
// Check if token has the correct role
92+
if (payload.role !== 'admin') {
93+
console.error('Invalid role in token')
94+
return false
95+
}
96+
97+
return true
7098
} catch (e) {
99+
console.error('Token verification failed:', e)
71100
return false
72101
}
73-
74-
return true
75102
}
76103
}))
77104
app.route('/v2', api)

src/v2.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ const addDuration = (index: number, data: IData): void => {
2828
}
2929

3030
const mostRecent = experience[index]
31-
if (typeof mostRecent.dateAsString !== 'string') {
31+
32+
// Do not add duration if we do not have starting date as parseable string, or
33+
// if there is a duration already defined
34+
if (typeof mostRecent.dateAsString !== 'string' || typeof mostRecent.duration != null) {
3235
return
3336
}
3437

0 commit comments

Comments
 (0)