105 lines
2.9 KiB
TypeScript
105 lines
2.9 KiB
TypeScript
|
import * as url from 'url'
|
||
|
import { ActivityPubActor } from '../../../shared/models/activitypub/activitypub-actor'
|
||
|
import { isRemoteAccountValid } from '../../helpers/custom-validators/activitypub/account'
|
||
|
import { logger } from '../../helpers/logger'
|
||
|
import { doRequest } from '../../helpers/requests'
|
||
|
import { ACTIVITY_PUB } from '../../initializers/constants'
|
||
|
import { database as db } from '../../initializers/database'
|
||
|
|
||
|
async function getOrCreateAccount (accountUrl: string) {
|
||
|
let account = await db.Account.loadByUrl(accountUrl)
|
||
|
|
||
|
// We don't have this account in our database, fetch it on remote
|
||
|
if (!account) {
|
||
|
const res = await fetchRemoteAccountAndCreateServer(accountUrl)
|
||
|
if (res === undefined) throw new Error('Cannot fetch remote account.')
|
||
|
|
||
|
// Save our new account in database
|
||
|
account = await res.account.save()
|
||
|
}
|
||
|
|
||
|
return account
|
||
|
}
|
||
|
|
||
|
async function fetchRemoteAccountAndCreateServer (accountUrl: string) {
|
||
|
const options = {
|
||
|
uri: accountUrl,
|
||
|
method: 'GET',
|
||
|
headers: {
|
||
|
'Accept': ACTIVITY_PUB.ACCEPT_HEADER
|
||
|
}
|
||
|
}
|
||
|
|
||
|
logger.info('Fetching remote account %s.', accountUrl)
|
||
|
|
||
|
let requestResult
|
||
|
try {
|
||
|
requestResult = await doRequest(options)
|
||
|
} catch (err) {
|
||
|
logger.warn('Cannot fetch remote account %s.', accountUrl, err)
|
||
|
return undefined
|
||
|
}
|
||
|
|
||
|
const accountJSON: ActivityPubActor = JSON.parse(requestResult.body)
|
||
|
if (isRemoteAccountValid(accountJSON) === false) {
|
||
|
logger.debug('Remote account JSON is not valid.', { accountJSON })
|
||
|
return undefined
|
||
|
}
|
||
|
|
||
|
const followersCount = await fetchAccountCount(accountJSON.followers)
|
||
|
const followingCount = await fetchAccountCount(accountJSON.following)
|
||
|
|
||
|
const account = db.Account.build({
|
||
|
uuid: accountJSON.uuid,
|
||
|
name: accountJSON.preferredUsername,
|
||
|
url: accountJSON.url,
|
||
|
publicKey: accountJSON.publicKey.publicKeyPem,
|
||
|
privateKey: null,
|
||
|
followersCount: followersCount,
|
||
|
followingCount: followingCount,
|
||
|
inboxUrl: accountJSON.inbox,
|
||
|
outboxUrl: accountJSON.outbox,
|
||
|
sharedInboxUrl: accountJSON.endpoints.sharedInbox,
|
||
|
followersUrl: accountJSON.followers,
|
||
|
followingUrl: accountJSON.following
|
||
|
})
|
||
|
|
||
|
const accountHost = url.parse(account.url).host
|
||
|
const serverOptions = {
|
||
|
where: {
|
||
|
host: accountHost
|
||
|
},
|
||
|
defaults: {
|
||
|
host: accountHost
|
||
|
}
|
||
|
}
|
||
|
const [ server ] = await db.Server.findOrCreate(serverOptions)
|
||
|
account.set('serverId', server.id)
|
||
|
|
||
|
return { account, server }
|
||
|
}
|
||
|
|
||
|
export {
|
||
|
getOrCreateAccount,
|
||
|
fetchRemoteAccountAndCreateServer
|
||
|
}
|
||
|
|
||
|
// ---------------------------------------------------------------------------
|
||
|
|
||
|
async function fetchAccountCount (url: string) {
|
||
|
const options = {
|
||
|
uri: url,
|
||
|
method: 'GET'
|
||
|
}
|
||
|
|
||
|
let requestResult
|
||
|
try {
|
||
|
requestResult = await doRequest(options)
|
||
|
} catch (err) {
|
||
|
logger.warn('Cannot fetch remote account count %s.', url, err)
|
||
|
return undefined
|
||
|
}
|
||
|
|
||
|
return requestResult.totalItems ? requestResult.totalItems : 0
|
||
|
}
|