Initial commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
.wrangler
|
||||||
19
README.md
Normal file
19
README.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Chookspace Pages
|
||||||
|
|
||||||
|
Create static sites detailing your projects!
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
1. Create an account on Chookspace.
|
||||||
|
2. Create a repo on Chookspace.
|
||||||
|
3. In that repo, create a `chookspace/` folder.
|
||||||
|
4. Put stuff to be hosted in the `chookspace/` folder (ideally include an index.html)
|
||||||
|
5. Visit `https://chsp.au/yourusername/yourrepo` to see your site!
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
This is a Cloudflare web worker which will do the following:
|
||||||
|
|
||||||
|
* If your useragent includes Git, you will be redirected to the Chookspace repo.
|
||||||
|
* If a Chookspace folder is found in the specified repo, and there is a corresponding file in the URL, that file will be proxied.
|
||||||
|
* If there is no file found, you will be redirected to that path on Chookspace.
|
||||||
1607
package-lock.json
generated
Normal file
1607
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
package.json
Normal file
18
package.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "chsp-worker",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Cloudflare Worker for chsp.au",
|
||||||
|
"main": "src/index.ts",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"deploy": "wrangler deploy"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"@cloudflare/workers-types": "^4.20230419.0",
|
||||||
|
"typescript": "^5.0.4",
|
||||||
|
"wrangler": "^3.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
106
src/index.ts
Normal file
106
src/index.ts
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
export interface Env {}
|
||||||
|
export interface ExecutionContext {}
|
||||||
|
|
||||||
|
function getMimeType(filename: string): string {
|
||||||
|
const ext = filename.split('.').pop()?.toLowerCase();
|
||||||
|
switch (ext) {
|
||||||
|
case 'html': return 'text/html';
|
||||||
|
case 'css': return 'text/css';
|
||||||
|
case 'js': return 'application/javascript';
|
||||||
|
case 'json': return 'application/json';
|
||||||
|
case 'png': return 'image/png';
|
||||||
|
case 'jpg':
|
||||||
|
case 'jpeg': return 'image/jpeg';
|
||||||
|
case 'gif': return 'image/gif';
|
||||||
|
case 'svg': return 'image/svg+xml';
|
||||||
|
case 'ico': return 'image/x-icon';
|
||||||
|
case 'txt': return 'text/plain';
|
||||||
|
case 'xml': return 'application/xml';
|
||||||
|
case 'pdf': return 'application/pdf';
|
||||||
|
case 'woff': return 'font/woff';
|
||||||
|
case 'woff2': return 'font/woff2';
|
||||||
|
case 'ttf': return 'font/ttf';
|
||||||
|
case 'otf': return 'font/otf';
|
||||||
|
case 'eot': return 'application/vnd.ms-fontobject';
|
||||||
|
case 'md': return 'text/markdown';
|
||||||
|
default: return 'application/octet-stream';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
||||||
|
const url = new URL(request.url);
|
||||||
|
const userAgent = request.headers.get('User-Agent') || '';
|
||||||
|
|
||||||
|
// 1. Check if request is coming from git
|
||||||
|
if (userAgent.toLowerCase().includes('git')) {
|
||||||
|
const redirectUrl = new URL(url.toString());
|
||||||
|
redirectUrl.hostname = 'chookspace.com';
|
||||||
|
return Response.redirect(redirectUrl.toString(), 302);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse path: /(user)/(repo)/(file...)
|
||||||
|
// Remove leading slash
|
||||||
|
const path = url.pathname.slice(1);
|
||||||
|
const parts = path.split('/');
|
||||||
|
|
||||||
|
// Need at least user and repo
|
||||||
|
// Otherwise, redirect to profile
|
||||||
|
if (parts.length < 2) {
|
||||||
|
const redirectUrl = new URL(url.toString());
|
||||||
|
redirectUrl.hostname = 'chookspace.com';
|
||||||
|
return Response.redirect(redirectUrl.toString(), 302);
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = parts[0];
|
||||||
|
const repo = parts[1];
|
||||||
|
let filePath = parts.slice(2).join('/');
|
||||||
|
|
||||||
|
// 2. Handle index.html default
|
||||||
|
if (!filePath || filePath === '') {
|
||||||
|
filePath = 'index.html';
|
||||||
|
} else if (filePath.endsWith('/')) {
|
||||||
|
filePath += 'index.html';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Check if file exists at raw URL
|
||||||
|
// URL structure: https://chookspace.com/(user)/(repo)/raw/branch/master/chookspace/(file)
|
||||||
|
const rawBase = `https://chookspace.com/${user}/${repo}/raw/branch/master/chookspace`;
|
||||||
|
const rawUrl = `${rawBase}/${filePath}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Prepare headers for the fetch request
|
||||||
|
const fetchHeaders = new Headers(request.headers);
|
||||||
|
fetchHeaders.set('User-Agent', 'Chsp-Worker-Proxy/1.0');
|
||||||
|
|
||||||
|
const rawResponse = await fetch(rawUrl, {
|
||||||
|
method: request.method,
|
||||||
|
headers: fetchHeaders,
|
||||||
|
redirect: 'follow'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 4. If success (2xx), proxy it
|
||||||
|
if (rawResponse.ok) {
|
||||||
|
const mimeType = getMimeType(filePath);
|
||||||
|
|
||||||
|
// Create new headers to override Content-Type
|
||||||
|
const newHeaders = new Headers(rawResponse.headers);
|
||||||
|
newHeaders.set('Content-Type', mimeType);
|
||||||
|
|
||||||
|
return new Response(rawResponse.body, {
|
||||||
|
status: rawResponse.status,
|
||||||
|
statusText: rawResponse.statusText,
|
||||||
|
headers: newHeaders
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Fetch failed (network error etc), proceed to fallback
|
||||||
|
console.error('Fetch error:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. If not found or error, redirect to chookspace site
|
||||||
|
const redirectUrl = new URL(url.toString());
|
||||||
|
redirectUrl.hostname = 'chookspace.com';
|
||||||
|
return Response.redirect(redirectUrl.toString(), 302);
|
||||||
|
},
|
||||||
|
};
|
||||||
19
tsconfig.json
Normal file
19
tsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es2021",
|
||||||
|
"lib": ["es2021", "webworker"],
|
||||||
|
"module": "es2022",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"types": ["@cloudflare/workers-types"],
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"checkJs": false,
|
||||||
|
"noEmit": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
||||||
6
wrangler.toml
Normal file
6
wrangler.toml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
name = "chsp-worker"
|
||||||
|
main = "src/index.ts"
|
||||||
|
compatibility_date = "2023-10-30"
|
||||||
|
|
||||||
|
[observability]
|
||||||
|
enabled = true
|
||||||
Reference in New Issue
Block a user