Add support for Plausible Analytics (#4)
* Added a dirty way to POST Plausible * Added some documentation * Made the documentation slightly better * Wrapped fetch in waitUntil * Apply suggestions from code review
This commit is contained in:
parent
15adcb9bd7
commit
45472515e0
2 changed files with 57 additions and 30 deletions
|
|
@ -12,13 +12,14 @@ Wrangler 2 is required now, but should be handled automatically for `yarn` comma
|
||||||
To run manual wrangler commands, try `npx wrangler`.
|
To run manual wrangler commands, try `npx wrangler`.
|
||||||
|
|
||||||
Simple steps:
|
Simple steps:
|
||||||
|
|
||||||
- `yarn install`
|
- `yarn install`
|
||||||
- `yarn addsecret`
|
- `yarn addsecret`
|
||||||
- `yarn deploy`
|
- `yarn deploy`
|
||||||
|
|
||||||
## Deploy (More involved)
|
## Deploy (More involved)
|
||||||
|
|
||||||
To deploy to your Cloudflare Workers account, edit the relevant entries in `wrangler.toml`, add a secret with `wrangler secret put WORKERLINKS_SECRET` and use `wrangler publish`.
|
To deploy to your Cloudflare Workers account, edit the relevant entries in `wrangler.toml`, add a secret with `wrangler secret put WORKERLINKS_SECRET` and use `wrangler publish`.
|
||||||
|
|
||||||
## Debugging
|
## Debugging
|
||||||
|
|
||||||
|
|
@ -83,6 +84,10 @@ It is a planned feature to be able to list all URLs via a `GET` on `/` with `Aut
|
||||||
For the time being you can view them from your Cloudflare Dashboard:
|
For the time being you can view them from your Cloudflare Dashboard:
|
||||||
Cloudflare Dashboard -> Workers -> KV -> View on the namespace.
|
Cloudflare Dashboard -> Workers -> KV -> View on the namespace.
|
||||||
|
|
||||||
|
## Plausible Analytics
|
||||||
|
|
||||||
|
To get statistics for your short URLs with Plausible Analytics, define a `PLAUSIBLE_HOST` secret set to the URL of your Plausible instance. For example, `https://plausible.io/`.
|
||||||
|
|
||||||
## Security
|
## Security
|
||||||
|
|
||||||
This code is relatively simple but still, if you find any security issues that can be exploited publicly, please reach out to me via email: `erisa (at) erisa.uk` with any relevant details.
|
This code is relatively simple but still, if you find any security issues that can be exploited publicly, please reach out to me via email: `erisa (at) erisa.uk` with any relevant details.
|
||||||
|
|
|
||||||
80
index.js
80
index.js
|
|
@ -1,14 +1,15 @@
|
||||||
let secret
|
let secret
|
||||||
|
|
||||||
addEventListener('fetch', (event) => {
|
addEventListener('fetch', (event) => {
|
||||||
event.respondWith(handleRequest(event.request))
|
event.respondWith(handleRequest(event))
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Respond to the request
|
* Respond to the request
|
||||||
* @param {Request} request
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
async function handleRequest(request) {
|
async function handleRequest(event) {
|
||||||
|
const { request } = event
|
||||||
// Set this in your worker's environment. wrangler.toml or cloudflare dashboard
|
// Set this in your worker's environment. wrangler.toml or cloudflare dashboard
|
||||||
if (WORKERLINKS_SECRET === undefined) {
|
if (WORKERLINKS_SECRET === undefined) {
|
||||||
return new Response('Secret is not defined. Please add WORKERLINKS_SECRET.')
|
return new Response('Secret is not defined. Please add WORKERLINKS_SECRET.')
|
||||||
|
|
@ -31,11 +32,11 @@ async function handleRequest(request) {
|
||||||
return Response.json(
|
return Response.json(
|
||||||
{
|
{
|
||||||
code: '405 Method Not Allowed',
|
code: '405 Method Not Allowed',
|
||||||
message: 'POST not valid for individual keys. Did you mean PUT?'
|
message: 'POST not valid for individual keys. Did you mean PUT?',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
status: 405
|
status: 405,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
key = '/' + Math.random().toString(36).slice(5)
|
key = '/' + Math.random().toString(36).slice(5)
|
||||||
|
|
@ -52,13 +53,34 @@ async function handleRequest(request) {
|
||||||
return Response.json(
|
return Response.json(
|
||||||
{
|
{
|
||||||
code: '404 Not Found',
|
code: '404 Not Found',
|
||||||
message: 'Key does not exist or has not propagated.'
|
message: 'Key does not exist or has not propagated.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
status: 404
|
status: 404,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
// PLAUSIBLE_HOST should be the full URL to your Plausible Analytics instance
|
||||||
|
// e.g. https://plausible.io/
|
||||||
|
if (PLAUSIBLE_HOST !== undefined) {
|
||||||
|
const url = PLAUSIBLE_HOST + 'api/event'
|
||||||
|
const headers = new Headers()
|
||||||
|
headers.append('User-Agent', request.headers.get('User-Agent'))
|
||||||
|
headers.append(
|
||||||
|
'X-Forwarded-For',
|
||||||
|
request.headers.get('X-Forwarded-For'),
|
||||||
|
)
|
||||||
|
headers.append('Content-Type', 'application/json')
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
name: 'pageview',
|
||||||
|
url: request.url,
|
||||||
|
domain: new URL(request.url).hostname,
|
||||||
|
}
|
||||||
|
event.waitUntil(
|
||||||
|
fetch(url, { method: 'POST', headers, body: JSON.stringify(data) }),
|
||||||
|
)
|
||||||
|
}
|
||||||
return new Response(null, { status: 302, headers: { Location: url } })
|
return new Response(null, { status: 302, headers: { Location: url } })
|
||||||
}
|
}
|
||||||
} else if (request.method == 'DELETE') {
|
} else if (request.method == 'DELETE') {
|
||||||
|
|
@ -66,11 +88,11 @@ async function handleRequest(request) {
|
||||||
return Response.json(
|
return Response.json(
|
||||||
{
|
{
|
||||||
code: '401 Unauthorized',
|
code: '401 Unauthorized',
|
||||||
message: 'Unauthorized.'
|
message: 'Unauthorized.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
status: 401
|
status: 401,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,11 +102,11 @@ async function handleRequest(request) {
|
||||||
return Response.json(
|
return Response.json(
|
||||||
{
|
{
|
||||||
code: '404 Not Found',
|
code: '404 Not Found',
|
||||||
message: 'Key does not exist or has not propagated.'
|
message: 'Key does not exist or has not propagated.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
status: 404,
|
status: 404,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
await kv.delete(key)
|
await kv.delete(key)
|
||||||
|
|
@ -93,11 +115,11 @@ async function handleRequest(request) {
|
||||||
message: 'Short URL deleted succesfully.',
|
message: 'Short URL deleted succesfully.',
|
||||||
key: key.substr(1),
|
key: key.substr(1),
|
||||||
shorturl: shorturl,
|
shorturl: shorturl,
|
||||||
longurl: url
|
longurl: url,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
status: 200
|
status: 200,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -106,11 +128,11 @@ async function handleRequest(request) {
|
||||||
{
|
{
|
||||||
code: '405 Method Not Allowed',
|
code: '405 Method Not Allowed',
|
||||||
message:
|
message:
|
||||||
'Unsupported method. Please use one of GET, PUT, POST, DELETE, HEAD.'
|
'Unsupported method. Please use one of GET, PUT, POST, DELETE, HEAD.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
status: 405
|
status: 405,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,11 +154,11 @@ async function putLink(givenSecret, shorturl, key, url) {
|
||||||
return Response.json(
|
return Response.json(
|
||||||
{
|
{
|
||||||
code: '401 Unauthorized',
|
code: '401 Unauthorized',
|
||||||
message: 'Unauthorized.'
|
message: 'Unauthorized.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
status: 401
|
status: 401,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -144,11 +166,11 @@ async function putLink(givenSecret, shorturl, key, url) {
|
||||||
return Response.json(
|
return Response.json(
|
||||||
{
|
{
|
||||||
code: '400 Bad Request',
|
code: '400 Bad Request',
|
||||||
message: "No valid URL given. Please set a 'URL' header."
|
message: "No valid URL given. Please set a 'URL' header.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
status: 400
|
status: 400,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,10 +180,10 @@ async function putLink(givenSecret, shorturl, key, url) {
|
||||||
message: 'URL created succesfully.',
|
message: 'URL created succesfully.',
|
||||||
key: key.substr(1),
|
key: key.substr(1),
|
||||||
shorturl: shorturl,
|
shorturl: shorturl,
|
||||||
longurl: url
|
longurl: url,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
status: 200
|
status: 200,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue