add actor HTML page with ostatus remote follow workflow. Fix #2
This commit is contained in:
parent
fbdb64ba37
commit
c67ea9f7ab
8 changed files with 2235 additions and 34 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,3 +3,5 @@ node_modules/
|
|||
config.json
|
||||
certs/
|
||||
.vscode
|
||||
dump/
|
||||
logs/
|
||||
|
|
32
index.js
32
index.js
|
@ -5,13 +5,21 @@ const fs = require('fs')
|
|||
const bodyParser = require('body-parser')
|
||||
const cors = require('cors')
|
||||
const https = require('https')
|
||||
const nunjucks = require('nunjucks')
|
||||
|
||||
const routes = require('./routes')
|
||||
const pub = require('./pub')
|
||||
const store = require('./store')
|
||||
const net = require('./net')
|
||||
const { DOMAIN, KEY_PATH, CERT_PATH, CA_PATH, PORT, PORT_HTTPS, DB_URL, DB_NAME } = require('./config.json')
|
||||
|
||||
const app = express()
|
||||
nunjucks.configure('templates', {
|
||||
autoescape: true,
|
||||
express: app,
|
||||
watch: app.get('env') === 'development'
|
||||
})
|
||||
|
||||
const client = new MongoClient(DB_URL, { useUnifiedTopology: true, useNewUrlParser: true })
|
||||
|
||||
const sslOptions = {
|
||||
|
@ -24,10 +32,7 @@ app.set('domain', DOMAIN)
|
|||
app.set('port', process.env.PORT || PORT)
|
||||
app.set('port-https', process.env.PORT_HTTPS || PORT_HTTPS)
|
||||
app.use(bodyParser.json({
|
||||
type: [
|
||||
'application/activity+json',
|
||||
'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'
|
||||
]
|
||||
type: pub.consts.jsonldTypes
|
||||
})) // support json encoded bodies
|
||||
app.use(bodyParser.urlencoded({ extended: true })) // support encoded bodies
|
||||
|
||||
|
@ -36,18 +41,17 @@ app.param('name', function (req, res, next, id) {
|
|||
next()
|
||||
})
|
||||
|
||||
// admin page
|
||||
app.use('/.well-known/webfinger', cors(), routes.webfinger)
|
||||
app.use('/u', cors(), routes.user)
|
||||
app.use('/o', cors(), routes.object)
|
||||
// json only routes
|
||||
app.use('/.well-known/webfinger', net.validators.jsonld, cors(), routes.webfinger)
|
||||
app.use('/o', net.validators.jsonld, cors(), routes.object)
|
||||
app.use('/s', net.validators.jsonld, cors(), routes.stream)
|
||||
app.use('/u/:name/inbox', net.validators.jsonld, routes.inbox)
|
||||
app.use('/u/:name/outbox', net.validators.jsonld, routes.outbox)
|
||||
|
||||
// admin page
|
||||
app.use('/.well-known/webfinger', cors(), routes.webfinger)
|
||||
// dual use routes
|
||||
app.use('/u', cors(), routes.user)
|
||||
app.use('/o', cors(), routes.object)
|
||||
app.use('/s', cors(), routes.stream)
|
||||
app.use('/u/:name/inbox', routes.inbox)
|
||||
app.use('/u/:name/outbox', routes.outbox)
|
||||
|
||||
// html/static routes
|
||||
app.use('/', express.static('public/www'))
|
||||
app.use('/f', express.static('public/files'))
|
||||
|
||||
|
|
|
@ -1,13 +1,29 @@
|
|||
const pub = require('../pub')
|
||||
|
||||
module.exports.activity = function activity (req, res, next) {
|
||||
module.exports = {
|
||||
activity,
|
||||
jsonld,
|
||||
outboxActivity
|
||||
}
|
||||
|
||||
function activity (req, res, next) {
|
||||
if (!pub.utils.validateActivity(req.body)) {
|
||||
return res.status(400).send('Invalid activity')
|
||||
}
|
||||
next()
|
||||
}
|
||||
|
||||
module.exports.outboxActivity = function outboxActivity (req, res, next) {
|
||||
function jsonld (req, res, next) {
|
||||
if (req.method === 'GET' && pub.consts.jsonldTypes.includes(req.get('Accept'))) {
|
||||
return next()
|
||||
}
|
||||
if (req.method === 'POST' && pub.consts.jsonldTypes.includes(req.get('Content-Type'))) {
|
||||
return next()
|
||||
}
|
||||
next('route')
|
||||
}
|
||||
|
||||
function outboxActivity (req, res, next) {
|
||||
if (!pub.utils.validateActivity(req.body)) {
|
||||
if (!pub.utils.validateObject(req.body)) {
|
||||
return res.status(400).send('Invalid activity')
|
||||
|
|
2075
package-lock.json
generated
2075
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -10,6 +10,7 @@
|
|||
"express-basic-auth": "^1.1.5",
|
||||
"http-signature": "github:wmurphyrd/node-http-signature#9c02eeb",
|
||||
"mongodb": "^3.3.2",
|
||||
"nunjucks": "^3.2.0",
|
||||
"request": "^2.88.0",
|
||||
"request-promise-native": "^1.0.7"
|
||||
},
|
||||
|
@ -17,6 +18,7 @@
|
|||
"node": ">=10.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chokidar": "^3.1.1",
|
||||
"standard": "^14.3.1",
|
||||
"standardjs": "^1.0.0-alpha"
|
||||
},
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
module.exports = {
|
||||
ASContext: 'https://www.w3.org/ns/activitystreams'
|
||||
ASContext: 'https://www.w3.org/ns/activitystreams',
|
||||
jsonldTypes: [
|
||||
'application/activity+json',
|
||||
'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||
'application/json'
|
||||
]
|
||||
}
|
||||
|
|
|
@ -2,21 +2,40 @@
|
|||
const express = require('express')
|
||||
const router = express.Router()
|
||||
const pub = require('../pub')
|
||||
const net = require('../net')
|
||||
|
||||
router.get('/:name', async function (req, res) {
|
||||
router.get('/:name', net.validators.jsonld, function (req, res) {
|
||||
const name = req.params.name
|
||||
if (!name) {
|
||||
return res.status(400).send('Bad request.')
|
||||
} else {
|
||||
const user = await pub.actor.getOrCreateActor(name)
|
||||
if (user) {
|
||||
return res.json(pub.utils.toJSONLD(user))
|
||||
}
|
||||
return res.status(404).send('Person not found')
|
||||
pub.actor.getOrCreateActor(name)
|
||||
.then(group => {
|
||||
return res.json(pub.utils.toJSONLD(group))
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
res.status(500).send(`Error creating group ${name}`)
|
||||
})
|
||||
})
|
||||
// HTML version
|
||||
router.get('/:name', function (req, res) {
|
||||
const name = req.params.name
|
||||
if (!name) {
|
||||
return res.status(400).send('Bad request.')
|
||||
}
|
||||
pub.actor.getOrCreateActor(name)
|
||||
.then(group => {
|
||||
const groupAcct = `${group.preferredUsername}@${req.app.get('domain')}`
|
||||
return res.render('group.html', { group, groupAcct })
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
res.status(500).send(`Error creating group ${name}`)
|
||||
})
|
||||
})
|
||||
|
||||
router.get('/:name/followers', function (req, res) {
|
||||
router.get('/:name/followers', net.validators.jsonld, function (req, res) {
|
||||
const name = req.params.name
|
||||
if (!name) {
|
||||
return res.status(400).send('Bad request.')
|
||||
|
|
96
templates/group.html
Normal file
96
templates/group.html
Normal file
|
@ -0,0 +1,96 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ group.preferredUsername }} group</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
<style>
|
||||
body {font-family: "Lato", sans-serif}
|
||||
.mySlides {display: none}
|
||||
</style>
|
||||
<script>
|
||||
function doFollow (evt) {
|
||||
let user, acct, username, domain
|
||||
evt.preventDefault();
|
||||
document.getElementById('username-error').classList.add('w3-hide')
|
||||
document.getElementById('finger-error').classList.add('w3-hide')
|
||||
try {
|
||||
user = document.getElementById('handle').value
|
||||
;[acct, username, domain] = /@?([^@]+)@(.+)/.exec(user)
|
||||
} catch (ignore) {
|
||||
document.getElementById('username-error').classList.remove('w3-hide')
|
||||
return
|
||||
}
|
||||
window.fetch(`https://${domain}/.well-known/webfinger?resource=acct:${acct}`, {
|
||||
method: 'get',
|
||||
mode: 'cors'
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(json => {
|
||||
const link = json.links.find(l => l.rel === 'http://ostatus.org/schema/1.0/subscribe')
|
||||
window.location.href = link.template.replace('{uri}', '{{ groupAcct }}')
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
document.getElementById('finger-error').classList.remove('w3-hide')
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Navbar -->
|
||||
<div class="w3-top">
|
||||
<div class="w3-bar w3-black w3-card">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Navbar on small screens (remove the onclick attribute if you want the navbar to always show on top of the content when clicking on the links) -->
|
||||
<div id="navDemo" class="w3-bar-block w3-black w3-hide w3-hide-large w3-hide-medium w3-top" style="margin-top:46px">
|
||||
|
||||
</div>
|
||||
<!-- Page content -->
|
||||
<div class="w3-content" style="max-width:2000px;margin-top:46px">
|
||||
|
||||
|
||||
<div class="w3-container w3-content w3-center w3-padding-64" style="max-width:800px" id="band">
|
||||
<h2 class="w3-wide">{{ group.preferredUsername }}</h2>
|
||||
<p class="w3-opacity"><i>{{ group.summary }}</i></p>
|
||||
<p class="w3-left-align">To join {{ group.preferredUsername }}, enter your handle below and you'll be
|
||||
redirected back to this group's profile in your app where you can follow it.</p>
|
||||
<form class="w3-container">
|
||||
<label>Your account</label>
|
||||
<input id="handle" class="w3-input w3-center" placeholder="user@example.com" type="text">
|
||||
<button class="w3-btn w3-cyan w3-block w3-margin-top" onclick="doFollow(event)">Procced to follow</button>
|
||||
</form>
|
||||
<div id="username-error" class="w3-hide w3-panel w3-pale-red w3-display-container w3-border">
|
||||
<span onclick="this.parentElement.classList.add('w3-hide')" class="w3-button w3-large w3-display-topright">×</span>
|
||||
<h3>Double check that username</h3>
|
||||
<p>e.g. you@yourhost.com</p>
|
||||
</div>
|
||||
<div id="finger-error" class="w3-hide w3-panel w3-pale-red w3-display-container w3-border">
|
||||
<span onclick="this.parentElement.classList.add('w3-hide')" class="w3-button w3-large w3-display-topright">×</span>
|
||||
<h3>Oops</h3>
|
||||
<p>Couldn't connect with your host.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- The Tour Section -->
|
||||
<!-- <div class="w3-black" id="tour">
|
||||
<div class="w3-container w3-content w3-padding-64" style="max-width:800px">
|
||||
<h2 class="w3-wide w3-center">Recent group posts</h2>
|
||||
</div> -->
|
||||
|
||||
<!-- End Page Content -->
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="w3-container w3-padding-64 w3-center w3-opacity w3-light-grey w3-xlarge">
|
||||
<a href="https://github.com/wmurphyrd/guppe"><i class="fa fa-github w3-hover-opacity"></i></a>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue