From f98820dafe688a5f5d00d574cf6d7dc9077c208c Mon Sep 17 00:00:00 2001 From: lesion Date: Mon, 29 Jul 2019 01:27:47 +0200 Subject: [PATCH] webfinger / AP user --- pages/login.vue | 3 +- pages/register.vue | 14 +++++++-- plugins/vue-awesome.js | 3 ++ server/api/index.js | 4 +-- server/federation/index.js | 30 +++++++++++++++++++ server/federation/webfinger.js | 27 +++++++++++++++++ server/index.js | 6 +++- .../migrations/20190728213923-add_username.js | 29 ++++++++++++++++++ .../20190728214848-add_displayname.js | 26 ++++++++++++++++ 9 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 server/federation/index.js create mode 100644 server/federation/webfinger.js create mode 100644 server/migrations/20190728213923-add_username.js create mode 100644 server/migrations/20190728214848-add_displayname.js diff --git a/pages/login.vue b/pages/login.vue index fd398fb3..81c43d1c 100644 --- a/pages/login.vue +++ b/pages/login.vue @@ -2,13 +2,14 @@ el-card nuxt-link.float-right(to='/') el-button(circle icon='el-icon-close' type='danger' size='small' plain) + h5 {{$t('common.login')}} el-form(v-loading='loading') p(v-html="$t('login.description')") el-input.mb-2(v-model='email' type='email' name='email' :placeholder='$t("common.email")' autocomplete='email' ref='email') - v-icon(name='user' slot='prepend') + v-icon(name='envelope' slot='prepend') el-input.mb-1(v-model='password' @keyup.enter.native="submit" name='password' type='password' :placeholder='$t("common.password")') diff --git a/pages/register.vue b/pages/register.vue index eb45e1d9..c4ba32b8 100644 --- a/pages/register.vue +++ b/pages/register.vue @@ -2,14 +2,19 @@ el-card nuxt-link.float-right(to='/') - v-icon(name='times' color='red') + el-button(circle icon='el-icon-close' type='danger' size='small' plain) h5 {{$t('common.register')}} el-form(@submit.native.prevent='register' method='POST' action='/api/user/register') p(v-html="$t('register.description')") + + el-input.mb-2(v-model='user.username' type='text' name='username' + :placeholder='$t("common.username")') + v-icon(name='user' slot='prepend') + el-input.mb-2(ref='email' v-model='user.email' type='email' required :placeholder='$t("common.email")' autocomplete='email' name='email') - span(slot='prepend') @ + v-icon(name='envelope' slot='prepend') el-input.mb-2(v-model='user.password' type="password" placeholder="Password" name='password' required) v-icon(name='lock' slot='prepend') @@ -34,6 +39,11 @@ export default { user: { } } }, + head () { + return { + title: this.settings.title + ' - ' + this.$t('common.register') + } + }, validate ({store}) { return store.state.settings.allow_registration }, diff --git a/plugins/vue-awesome.js b/plugins/vue-awesome.js index d1d925d2..272a74f5 100644 --- a/plugins/vue-awesome.js +++ b/plugins/vue-awesome.js @@ -1,4 +1,6 @@ import Vue from 'vue' +// https://fontawesome.com/icons?d=gallery +// import 'vue-awesome/icons/lock' import 'vue-awesome/icons/user' import 'vue-awesome/icons/plus' @@ -25,6 +27,7 @@ import 'vue-awesome/icons/chevron-right' import 'vue-awesome/icons/chevron-left' import 'vue-awesome/icons/search' import 'vue-awesome/icons/times' +import 'vue-awesome/icons/envelope' import 'vue-awesome/icons/calendar-day' import 'vue-awesome/icons/calendar-week' import 'vue-awesome/icons/calendar-alt' diff --git a/server/api/index.js b/server/api/index.js index 798aa3fe..f6bf12dd 100644 --- a/server/api/index.js +++ b/server/api/index.js @@ -102,7 +102,7 @@ api.get('/event/:month/:year', eventController.getAll) // api.get('/event/:month/:year', eventController.getAfter) // mastodon oauth auth -api.post('/settings/getauthurl', jwt, isAuth, isAdmin, settingsController.getAuthURL) -api.get('/settings/oauth', jwt, isAuth, isAdmin, settingsController.code) +//api.post('/settings/getauthurl', jwt, isAuth, isAdmin, settingsController.getAuthURL) +//api.get('/settings/oauth', jwt, isAuth, isAdmin, settingsController.code) module.exports = api diff --git a/server/federation/index.js b/server/federation/index.js new file mode 100644 index 00000000..4b112c6e --- /dev/null +++ b/server/federation/index.js @@ -0,0 +1,30 @@ +const express = require('express') +const router = express.Router() +const { user: User } = require('../api/models') +const config = require('config') + +router.get('/u/:name', async (req, res) => { + const name = req.params.name + if (!name) return res.status(400).send('Bad request.') + const user = await User.findOne({where: { username: name }}) + if (!user) return res.status(404).send(`No record found for ${name}`) + const domain = 'local' + const ret = { + '@context': [ + 'https://www.w3.org/ns/activitystreams', + 'https://w3id.org/security/v1' + ], + 'id': `${config.baseurl}/federation/u/${name}`, + 'type': 'Person', + 'preferredUsername': name, + 'inbox': `${config.baseurl}/federation/inbox`, + 'followers': `${config.baseurl}/federation/u/${name}/followers`, + 'publicKey': { + 'id': `${config.baseurl}/federation/u/${name}#main-key`, + 'owner': `${config.baseurl}/federation/u/${name}`, + 'publicKeyPem': user.pubkey + } + } + res.json(ret) +}) +module.exports = router diff --git a/server/federation/webfinger.js b/server/federation/webfinger.js new file mode 100644 index 00000000..53760358 --- /dev/null +++ b/server/federation/webfinger.js @@ -0,0 +1,27 @@ +const express = require('express') +const router = express.Router() +const { user: User } = require('../api/models') +const config = require('config') + +router.get('/', async (req, res) => { + const resource = req.query.resource + if (!resource || !resource.includes('acct:')) { + return res.status(400).send('Bad request. Please make sure "acct:USER@DOMAIN" is what you are sending as the "resource" query parameter.') + } + const name = resource.replace('acct:', '') + const domain = 'localhoasf' + const user = await User.findOne({where: { username: name } }) + if (!user) return res.status(404).send(`No record found for ${name}`) + const ret = { + subject: `acct:${name}:${domain}`, + links: [ + { + rel: 'self', + type: 'application/activity+json', + href: `${config.baseurl}/federation/u/${name}` + } + ] + } + res.json(ret) +}) +module.exports = router diff --git a/server/index.js b/server/index.js index d977a156..d8b69b9e 100644 --- a/server/index.js +++ b/server/index.js @@ -3,6 +3,7 @@ const path = require('path') const express = require('express') const consola = require('consola') const morgan = require('morgan') +const cors = require('cors') const { Nuxt, Builder } = require('nuxt') // Import and Set Nuxt.js options @@ -24,12 +25,15 @@ async function start() { } // configurable favicon && logo - app.use('/favicon.ico', express.static(path.resolve(config.favicon))) + app.use('/favicon.ico', express.static(path.resolve(config.favicon || 'assets/favicon.ico'))) app.use(morgan('dev')) app.use('/media/', express.static(config.upload_path)) app.use('/api', require('./api/index')) + app.use('/.well-known/webfinger', cors(), require('./federation/webfinger')) + app.use('/federation', cors(), require('./federation')) + // Give nuxt middleware to express app.use(nuxt.render) diff --git a/server/migrations/20190728213923-add_username.js b/server/migrations/20190728213923-add_username.js new file mode 100644 index 00000000..8c1950a8 --- /dev/null +++ b/server/migrations/20190728213923-add_username.js @@ -0,0 +1,29 @@ +'use strict'; + +module.exports = { + up: (queryInterface, Sequelize) => { + return queryInterface.addColumn('users', 'username', { + type: Sequelize.STRING, + index: true, + allowNull: false, + defaultValue: '' + }) + /* + Add altering commands here. + Return a promise to correctly handle asynchronicity. + + Example: + return queryInterface.createTable('users', { id: Sequelize.INTEGER }); + */ + }, + + down: (queryInterface, Sequelize) => { + /* + Add reverting commands here. + Return a promise to correctly handle asynchronicity. + + Example: + return queryInterface.dropTable('users'); + */ + } +}; diff --git a/server/migrations/20190728214848-add_displayname.js b/server/migrations/20190728214848-add_displayname.js new file mode 100644 index 00000000..073d611e --- /dev/null +++ b/server/migrations/20190728214848-add_displayname.js @@ -0,0 +1,26 @@ +'use strict'; + +module.exports = { + up: (queryInterface, Sequelize) => { + return queryInterface.addColumn('users', 'display_name', { + type: Sequelize.STRING + }) + /* + Add altering commands here. + Return a promise to correctly handle asynchronicity. + + Example: + return queryInterface.createTable('users', { id: Sequelize.INTEGER }); + */ + }, + + down: (queryInterface, Sequelize) => { + /* + Add reverting commands here. + Return a promise to correctly handle asynchronicity. + + Example: + return queryInterface.dropTable('users'); + */ + } +};