-
Notifications
You must be signed in to change notification settings - Fork 5
/
index.js
153 lines (136 loc) · 3.99 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// settings
const createNewBookmarksEnabled = true
// end of settings
const cors = {
'Content-Type': 'application/json',
'Access-Control-Allow-Methods': 'GET, POST, PUT',
'Access-Control-Allow-Origin': 'chrome-extension://lcbjdhceifofjlpecfpeimnnphbcjgnc',
'Access-Control-Allow-Headers': 'Content-Type, Accept-Version',
};
// KV binding XBSKV must be available
if (typeof XBSKV === 'undefined') {
addEventListener('fetch', event => {
event.respondWith(
new Response(
'XBSKV is not defined, please check KV Namespace Bindings.',
{ status: 500 },
),
)
})
} else {
addEventListener('fetch', event => {
event.respondWith(
handleRequest(event.request).catch(
err => new Response(err.stack, { status: 500 }),
),
)
})
}
/**
* @param {Request} request
* @returns {Promise<Response>}
*/
const handleRequest = async request => {
const { pathname } = new URL(request.url)
if (request.method === 'OPTIONS') {
return jsonToResponse('')
}
// service info
if (pathname === '/info') {
return handleServiceInfo()
}
// bookmarks apis
if (pathname.startsWith('/bookmarks')) {
const paths = pathname
.replace('/bookmarks', '')
.split('/')
.filter(p => p)
if (request.method === 'POST' && paths.length === 0) {
return await handlePostBookmarks(await request.json())
}
if (request.method === 'PUT' && paths.length === 1) {
return await hanldePutBookmarks(paths[0], await request.json())
}
if (request.method === 'GET' && paths.length >= 1) {
return await handleGetBookmarks(paths)
}
}
return sendError('not found', 404)
}
const jsonToResponse = json => {
return new Response(JSON.stringify(json), {
headers: Object.assign({ 'Content-Type': 'application/json' }, cors)
})
}
const sendError = (text, err) => {
return new Response(text, {
status: err || 400,
headers: Object.assign({ 'Content-Type': 'text/plain' }, cors)
})
}
const handleServiceInfo = () => {
return jsonToResponse({
maxSyncSize: 104857600,
message: 'Welcome to xbrowsersync-cfw.',
status: createNewBookmarksEnabled ? 1 : 3,
version: '1.1.13',
})
}
const handlePostBookmarks = async jsonBody => {
if (!createNewBookmarksEnabled) {
return sendError('bookmarks creation disabled')
}
if (jsonBody.version == null) {
return sendError('missing version input')
}
// set version and lastUpdated to KV
const bid = hexUUID()
const lastUpdated = new Date().toISOString()
await XBSKV.put(`${bid}_version`, jsonBody.version)
await XBSKV.put(`${bid}_lastUpdated`, lastUpdated)
return jsonToResponse({
id: bid,
lastUpdated,
version: jsonBody.version,
})
}
const hanldePutBookmarks = async (bid, jsonBody) => {
if (!jsonBody.bookmarks) {
return sendError('missing bookmarks input')
}
if (!jsonBody.lastUpdated) {
return sendError('missing lastUpdated input')
}
const lastUpdatedInDB = await XBSKV.get(`${bid}_lastUpdated`)
if (lastUpdatedInDB !== jsonBody.lastUpdated) {
return sendError('A sync conflict was detected')
}
const newLastUpdated = new Date().toISOString()
await XBSKV.put(`${bid}`, jsonBody.bookmarks)
await XBSKV.put(`${bid}_lastUpdated`, newLastUpdated)
return jsonToResponse({ lastUpdated: newLastUpdated })
}
const handleGetBookmarks = async paths => {
const lastUpdated = await XBSKV.get(`${paths[0]}_lastUpdated`)
if (paths.length >= 2 && paths[1] === 'lastUpdated') {
return jsonToResponse({ lastUpdated })
}
const version = await XBSKV.get(`${paths[0]}_version`)
if (paths.length >= 2 && paths[1] === 'version') {
return jsonToResponse({ version })
}
const result = {
version,
lastUpdated,
}
const bookmarks = await XBSKV.get(`${paths[0]}`)
if (bookmarks) {
result.bookmarks = bookmarks
}
return jsonToResponse(result)
}
const hexUUID = () => {
const arr = new Uint8Array(16)
crypto.getRandomValues(arr)
return [...arr].map(x => x.toString(16).padStart(2, '0')).join('')
}