summaryrefslogtreecommitdiff
path: root/packages/megalodon/src/detector.ts
blob: ba95d96816b8eded4528f79986e66f500ec6c28f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import axios, { AxiosRequestConfig } from 'axios'
import { NodeinfoError } from './megalodon'

const NODEINFO_10 = 'http://nodeinfo.diaspora.software/ns/schema/1.0'
const NODEINFO_20 = 'http://nodeinfo.diaspora.software/ns/schema/2.0'
const NODEINFO_21 = 'http://nodeinfo.diaspora.software/ns/schema/2.1'

type Links = {
  links: Array<Link>
}

type Link = {
  href: string
  rel: string
}

type Nodeinfo10 = {
  software: Software
  metadata: Metadata
}

type Nodeinfo20 = {
  software: Software
  metadata: Metadata
}

type Nodeinfo21 = {
  software: Software
  metadata: Metadata
}

type Software = {
  name: string
}

type Metadata = {
  upstream?: {
    name: string
  }
}

/**
 * Detect SNS type.
 * Now support Mastodon, Pleroma and Pixelfed. Throws an error when no known platform can be detected.
 *
 * @param url Base URL of SNS.
 * @return SNS name.
 */
export const detector = async (
  url: string,
): Promise<'mastodon' | 'pleroma' | 'misskey' | 'friendica'> => {
  let options: AxiosRequestConfig = {
    timeout: 20000
  }

  const res = await axios.get<Links>(url + '/.well-known/nodeinfo', options)
  const link = res.data.links.find(l => l.rel === NODEINFO_20 || l.rel === NODEINFO_21)
  if (!link) throw new NodeinfoError('Could not find nodeinfo')
  switch (link.rel) {
    case NODEINFO_10: {
      const res = await axios.get<Nodeinfo10>(link.href, options)
      switch (res.data.software.name) {
        case 'pleroma':
          return 'pleroma'
        case 'akkoma':
          return 'pleroma'
        case 'mastodon':
          return 'mastodon'
        case "wildebeest":
          return "mastodon"
        case 'misskey':
          return 'misskey'
        case 'friendica':
          return 'friendica'
        default:
          if (res.data.metadata.upstream?.name && res.data.metadata.upstream.name === 'mastodon') {
            return 'mastodon'
          }
          throw new NodeinfoError('Unknown SNS')
      }
    }
    case NODEINFO_20: {
      const res = await axios.get<Nodeinfo20>(link.href, options)
      switch (res.data.software.name) {
        case 'pleroma':
          return 'pleroma'
        case 'akkoma':
          return 'pleroma'
        case 'mastodon':
          return 'mastodon'
        case "wildebeest":
          return "mastodon"
        case 'misskey':
          return 'misskey'
        case 'friendica':
          return 'friendica'
        default:
          if (res.data.metadata.upstream?.name && res.data.metadata.upstream.name === 'mastodon') {
            return 'mastodon'
          }
          throw new NodeinfoError('Unknown SNS')
      }
    }
    case NODEINFO_21: {
      const res = await axios.get<Nodeinfo21>(link.href, options)
      switch (res.data.software.name) {
        case 'pleroma':
          return 'pleroma'
        case 'akkoma':
          return 'pleroma'
        case 'mastodon':
          return 'mastodon'
        case "wildebeest":
          return "mastodon"
        case 'misskey':
          return 'misskey'
        case 'friendica':
          return 'friendica'
        default:
          if (res.data.metadata.upstream?.name && res.data.metadata.upstream.name === 'mastodon') {
            return 'mastodon'
          }
          throw new NodeinfoError('Unknown SNS')
      }
    }
    default:
      throw new NodeinfoError('Could not find nodeinfo')
  }
}