Added register account API + Changes needed

* Added .env to .gitignore
* New dependencies on package.json
* Moved database connection to a "db.js" module
* Changed API ActivityPub params
* Added new APIs on "server.js"
* Added needed env variables on .env
This commit is contained in:
Niko 2022-02-08 22:22:42 +01:00
parent dbd336be33
commit 95436a59b3
10 changed files with 160 additions and 46 deletions

2
.gitignore vendored
View File

@ -1,6 +1,6 @@
*.swp
package-lock.json
env.example
.env
_dev/db/
node_modules/

3
api/src/api-utils.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
url: (path) => { return '/api/v1' + path },
}

4
api/src/api.js Normal file
View File

@ -0,0 +1,4 @@
module.exports = {
url: require('./api-utils.js').url,
accounts: require('./api/accounts.js')
}

38
api/src/api/accounts.js Normal file
View File

@ -0,0 +1,38 @@
const api = require('../api-utils.js')
const db = require('../db.js')
const pwd = require('../passwd.js')
module.exports = {
register: {
post: async (req, res) => {
if (req.body.username !== undefined &&
req.body.email !== undefined &&
req.body.password !== undefined &&
req.body.password2 !== undefined) {
// TODO: validate values, sanitize and check captcha or other registration limitations
console.log(req.body)
if (req.body.password !== req.body.password2)
return res.status(400).json({ error: 'passwords_not_match' })
if (await db.table.users().findOne({ username: req.body.username }) != null)
return res.status(403).json({ error: 'username_already_exists' })
if (await db.table.users().findOne({ email: req.body.email }) !== null)
return res.status(403).json({ error: 'email_already_exists' })
const documen = await db.table.users().insertOne({
'username': req.body.username,
'email': req.body.email,
'password': pwd.cryptPassword(req.body.password)
})
if (documen.insertedCount > 0)
return res.json({ result: documen.insertedId })
return res.status(500).json({ error: 'unknown_error' })
}
return res.status(400).json({ error: 'invalid_params' })
},
}
}

23
api/src/db.js Normal file
View File

@ -0,0 +1,23 @@
const { MongoClient } = require('mongodb')
global.mconn = null
global.mdb = null
module.exports = {
conn: () => {
if (mconn !== null)
return mconn
const dbhost = process.env.DB_HOST || 'db'
mconn = new MongoClient('mongodb://'+dbhost+':27017', {
useUnifiedTopology: true,
useNewUrlParser: true
})
return mconn
},
get: () => {
mdb = mconn.db(process.env.DB_NAME || 'activitypub')
return mdb
},
table: {
users: () => { return mdb.collection('u__users') },
},
}

View File

@ -1,5 +1,8 @@
{
"dependencies": {
"activitypub-express": "^2.3.0"
"activitypub-express": "^2.3.0",
"bcrypt": "^5.0.1",
"deasync": "^0.1.24",
"node-gyp": "^8.4.1"
}
}

27
api/src/passwd.js Normal file
View File

@ -0,0 +1,27 @@
const bcrypt = require('bcrypt')
const deasync = require('deasync')
exports.cryptPassword = (password) => {
var theSalt = -1
bcrypt.genSalt(10, (err, salt) => {
if (err) theSalt = null
else theSalt = salt
})
while (theSalt == -1) deasync.runLoopOnce()
var theHash = -1
bcrypt.hash(password, theSalt, (err, hash) => {
if (err) theHash = null
else theHash = hash
})
while (theHash == -1) deasync.runLoopOnce()
return theHash
}
exports.comparePassword = (plainPass, hashword) => {
var isPasswordMatch = -1
bcrypt.compare(plainPass, hashword, (err, matches) => {
isPasswordMatch = err === undefined && matches
})
while (isPasswordMatch == -1) deasync.runLoopOnce()
return isPasswordMatch
}

View File

@ -1,47 +1,50 @@
const express = require('express')
const { MongoClient } = require('mongodb')
const db = require('./db.js')
const ActivitypubExpress = require('activitypub-express')
const port = 8080
const app = express()
const bodyParser = require('body-parser')
const routes = {
actor: '/u/:actor',
object: '/o/:id',
activity: '/s/:id',
inbox: '/u/:actor/inbox',
outbox: '/u/:actor/outbox',
followers: '/u/:actor/followers',
following: '/u/:actor/following',
liked: '/u/:actor/liked',
collections: '/u/:actor/c/:id',
blocked: '/u/:actor/blocked',
rejections: '/u/:actor/rejections',
rejected: '/u/:actor/rejected',
shares: '/s/:id/shares',
likes: '/s/:id/likes'
actor: '/u/:actor',
object: '/o/:id',
activity: '/s/:id',
inbox: '/u/:actor/inbox',
outbox: '/u/:actor/outbox',
followers: '/u/:actor/followers',
following: '/u/:actor/following',
liked: '/u/:actor/liked',
collections: '/u/:actor/c/:id',
blocked: '/u/:actor/blocked',
rejections: '/u/:actor/rejections',
rejected: '/u/:actor/rejected',
shares: '/s/:id/shares',
likes: '/s/:id/likes'
}
const apex = ActivitypubExpress({
name: 'Apex Example',
version: '1.0.0',
domain: 'localhost',
actorParam: 'actor',
objectParam: 'id',
activityParam: 'id',
routes
})
const client = new MongoClient('mongodb://db:27017', {
useUnifiedTopology: true,
useNewUrlParser: true
name: 'FediLove ActivityPub API',
version: '0.0.1',
domain: process.env.DOMAIN,
actorParam: 'actor',
objectParam: 'id',
activityParam: 'id',
routes
})
const api = require('./api.js')
const dbhost = process.env.DB_HOST || 'db'
const client = db.conn()
// extensions for express
app.use(express.json({ type: apex.consts.jsonldTypes }), apex)
app.use(bodyParser.urlencoded({ extended: true }))
// define routes using prepacakged middleware collections
app.route(routes.inbox)
.get(apex.net.inbox.get)
.post(apex.net.inbox.post)
.get(apex.net.inbox.get)
.post(apex.net.inbox.post)
app.route(routes.outbox)
.get(apex.net.outbox.get)
.post(apex.net.outbox.post)
.get(apex.net.outbox.get)
.post(apex.net.outbox.post)
app.get(routes.actor, apex.net.actor.get)
app.get(routes.followers, apex.net.followers.get)
app.get(routes.following, apex.net.following.get)
@ -56,21 +59,27 @@ app.get('/nodeinfo/:version', apex.net.nodeInfo.get)
// custom side-effects for your app
app.on('apex-outbox', msg => {
if (msg.activity.type === 'Create') {
console.log(`New ${msg.object.type} from ${msg.actor}`)
}
if (msg.activity.type === 'Create') {
console.log(`New ${msg.object.type} from ${msg.actor}`)
}
})
app.on('apex-inbox', msg => {
if (msg.activity.type === 'Create') {
console.log(`New ${msg.object.type} from ${msg.actor} to ${msg.recipient}`)
}
if (msg.activity.type === 'Create') {
console.log(`New ${msg.object.type} from ${msg.actor} to ${msg.recipient}`)
}
})
// API defines
app.route(api.url('/accounts/register'))
.post(api.accounts.register.post)
// initialize
client.connect({ useNewUrlParser: true })
.then(() => {
apex.store.db = client.db('DB_NAME')
return apex.store.setup()
})
.then(() => {
app.listen(port, () => console.log(`apex app listening on port ${port}`))
})
.then(() => {
apex.store.db = db.get()
return apex.store.setup()
})
.then(() => {
app.listen(port, () => console.log(`ActivityPub API listening on: 0.0.0.0:${port}`))
})

View File

@ -15,7 +15,8 @@ services:
- ./api/src:/src
environment:
- DOMAIN=${DOMAIN}
- MONGO_DB=db
- DB_HOST=${DB_HOST}
- DB_NAME=${DB_NAME}
working_dir: /src
networks:
- fedilove

6
env.example Normal file
View File

@ -0,0 +1,6 @@
# Instance
DOMAIN=example.org
# Database
DB_HOST=db
DB_NAME=fedilove