8 changed files with 1822 additions and 1 deletions
-
4.env
-
1.gitignore
-
118app.js
-
1668package-lock.json
-
11package.json
-
8static/app.js
-
13static/index.html
-
0static/style.css
@ -0,0 +1,4 @@ |
|||
export GITEA_API_BASE=https://gitea.benatkin.com/api/v1 |
|||
export GITEA_USER=ben |
|||
export GITEA_REPO=notes |
|||
export GITEA_TOKEN=a1ba576e25dca938172496eebab5c35ed88a2889 |
|||
@ -0,0 +1 @@ |
|||
node_modules |
|||
@ -0,0 +1,118 @@ |
|||
const Koa = require('koa'); |
|||
const Router = require('@koa/router'); |
|||
const serve = require('koa-static'); |
|||
const bodyParser = require('koa-bodyparser'); |
|||
const fetch = require('isomorphic-unfetch'); |
|||
const randomBytes = require('crypto').randomBytes; |
|||
|
|||
const app = new Koa(); |
|||
const router = new Router(); |
|||
|
|||
const gitea = { |
|||
apiBase: process.env.GITEA_API_BASE, |
|||
user: process.env.GITEA_USER, |
|||
repo: process.env.GITEA_REPO, |
|||
token: process.env.GITEA_TOKEN, |
|||
}; |
|||
|
|||
async function createNote(name, contentPlain) { |
|||
const content = Buffer.from(contentPlain).toString('base64'); |
|||
const body = JSON.stringify({content}); |
|||
const url = `${gitea.apiBase}/repos/${gitea.user}/${gitea.repo}/contents/${name}.txt`; |
|||
const resp = await fetch(url, { |
|||
method: 'POST', |
|||
headers: { |
|||
Accept: 'application/json', |
|||
'Content-Type': 'application/json', |
|||
Authorization: `token ${gitea.token}`, |
|||
}, |
|||
body, |
|||
}); |
|||
console.log({url, resp}); |
|||
} |
|||
|
|||
async function appendNote(content) { |
|||
const originalResp = await fetch(`${gitea.apiBase}/repos/${gitea.user}/${gitea.repo}/contents/notes.txt`, { |
|||
headers: { |
|||
Accept: 'application/json', |
|||
Authorization: `token ${gitea.token}`, |
|||
}, |
|||
}); |
|||
const originalData = await originalResp.json(); |
|||
const originalContentPlain = Buffer.from(originalData.content, 'base64').toString('utf8'); |
|||
const newContentPlain = originalContentPlain + "\n\n" + content; |
|||
const newContent = Buffer.from(newContentPlain).toString('base64'); |
|||
const body = JSON.stringify({content: newContent, sha: originalData.sha}); |
|||
const resp = await fetch(`${gitea.apiBase}/repos/${gitea.user}/${gitea.repo}/contents/notes.txt`, { |
|||
method: 'PUT', |
|||
headers: { |
|||
Accept: 'application/json', |
|||
'Content-Type': 'application/json', |
|||
Authorization: `token ${gitea.token}`, |
|||
}, |
|||
body, |
|||
}); |
|||
} |
|||
|
|||
router.post('/micropub', async (ctx, next) => { |
|||
const resp = await fetch('https://tokens.indieauth.com/token', { |
|||
method: 'GET', |
|||
headers: { |
|||
Accept: 'application/json', |
|||
Authorization: ctx.headers['authorization'] |
|||
} |
|||
}); |
|||
const data = await resp.json(); |
|||
if (!resp.ok) { |
|||
next(); |
|||
return; |
|||
} |
|||
const name = randomBytes(12).toString('hex'); |
|||
await createNote(name, ctx.request.body.content); |
|||
ctx.set('Location', `https://${name}.benatkin.com/`); |
|||
ctx.status = 201; |
|||
ctx.body = {}; |
|||
}); |
|||
|
|||
router.get('/', async (ctx, next) => { |
|||
const host = (ctx.headers['host'] || '').replace(/\.[^.]+\.[^.*]+$/, '') |
|||
if (host === 'notes') { |
|||
return await next(); |
|||
} |
|||
const url = `${gitea.apiBase}/repos/${gitea.user}/${gitea.repo}/contents/${encodeURIComponent(host)}.txt`; |
|||
const resp = await fetch(url, { |
|||
headers: { |
|||
Accept: 'application/json', |
|||
Authorization: `token ${gitea.token}`, |
|||
}, |
|||
}); |
|||
console.log({url, resp}); |
|||
if (resp.ok) { |
|||
const { content } = await resp.json(); |
|||
const contentPlain = Buffer.from(content, 'base64').toString('utf8'); |
|||
ctx.body = contentPlain; |
|||
} else { |
|||
ctx.status = 404; |
|||
ctx.body = `${host} not found`; |
|||
} |
|||
}) |
|||
|
|||
router.get('/api/notes', async (ctx, next) => { |
|||
const resp = await fetch(`${gitea.apiBase}/repos/${gitea.user}/${gitea.repo}/contents/notes.txt`, { |
|||
headers: { |
|||
Accept: 'application/json', |
|||
Authorization: `token ${gitea.token}`, |
|||
}, |
|||
}); |
|||
const { content } = await resp.json(); |
|||
const contentPlain = Buffer.from(content, 'base64').toString('utf8'); |
|||
ctx.body = { content: contentPlain }; |
|||
}); |
|||
|
|||
app |
|||
.use(bodyParser()) |
|||
.use(router.routes()) |
|||
.use(router.allowedMethods()) |
|||
.use(serve('static')); |
|||
|
|||
app.listen(3000); |
|||
1668
package-lock.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,8 @@ |
|||
async function getData() { |
|||
const resp = await fetch('/api/notes'); |
|||
const data = await resp.json(); |
|||
const el = document.getElementById('notes'); |
|||
el.innerText = data.content; |
|||
} |
|||
|
|||
getData(); |
|||
@ -0,0 +1,13 @@ |
|||
<!doctype html> |
|||
<head> |
|||
<title>Notes</title> |
|||
<link rel="me" href="https://github.com/benatkin"> |
|||
<link rel="micropub" href="https://notes.benatkin.com/micropub"> |
|||
<link rel="token_endpoint" href="https://tokens.indieauth.com/token"> |
|||
<link rel="authorization_endpoint" href="https://indieauth.com/auth"> |
|||
<link rel="stylesheet" href="/style.css"> |
|||
<script type="module" src="/app.js"></script> |
|||
<body> |
|||
<pre id="notes"></pre> |
|||
</body> |
|||
</head> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue