Split types and typings
[oweals/peertube.git] / server / helpers / webfinger.ts
1 import * as WebFinger from 'webfinger.js'
2 import { WebFingerData } from '../../shared'
3 import { ActorModel } from '../models/activitypub/actor'
4 import { isTestInstance } from './core-utils'
5 import { isActivityPubUrlValid } from './custom-validators/activitypub/misc'
6 import { WEBSERVER } from '../initializers/constants'
7 import { MActorFull } from '../types/models'
8
9 const webfinger = new WebFinger({
10   webfist_fallback: false,
11   tls_only: isTestInstance(),
12   uri_fallback: false,
13   request_timeout: 3000
14 })
15
16 async function loadActorUrlOrGetFromWebfinger (uriArg: string) {
17   // Handle strings like @toto@example.com
18   const uri = uriArg.startsWith('@') ? uriArg.slice(1) : uriArg
19
20   const [ name, host ] = uri.split('@')
21   let actor: MActorFull
22
23   if (!host || host === WEBSERVER.HOST) {
24     actor = await ActorModel.loadLocalByName(name)
25   } else {
26     actor = await ActorModel.loadByNameAndHost(name, host)
27   }
28
29   if (actor) return actor.url
30
31   return getUrlFromWebfinger(uri)
32 }
33
34 async function getUrlFromWebfinger (uri: string) {
35   const webfingerData: WebFingerData = await webfingerLookup(uri)
36   return getLinkOrThrow(webfingerData)
37 }
38
39 // ---------------------------------------------------------------------------
40
41 export {
42   getUrlFromWebfinger,
43   loadActorUrlOrGetFromWebfinger
44 }
45
46 // ---------------------------------------------------------------------------
47
48 function getLinkOrThrow (webfingerData: WebFingerData) {
49   if (Array.isArray(webfingerData.links) === false) throw new Error('WebFinger links is not an array.')
50
51   const selfLink = webfingerData.links.find(l => l.rel === 'self')
52   if (selfLink === undefined || isActivityPubUrlValid(selfLink.href) === false) {
53     throw new Error('Cannot find self link or href is not a valid URL.')
54   }
55
56   return selfLink.href
57 }
58
59 function webfingerLookup (nameWithHost: string) {
60   return new Promise<WebFingerData>((res, rej) => {
61     webfinger.lookup(nameWithHost, (err, p) => {
62       if (err) return rej(err)
63
64       return res(p.object)
65     })
66   })
67 }