@unavatar/core 3.7.61 → 3.7.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/package.json +6 -2
- package/src/index.js +9 -1
- package/src/providers/index.js +4 -0
- package/src/providers/linkedin.js +8 -0
- package/src/providers/mastodon.js +58 -0
- package/src/util/is-reserved-ip.js +23 -0
package/README.md
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
- [Google](#google)
|
|
18
18
|
- [Gravatar](#gravatar)
|
|
19
19
|
- [Instagram](#instagram)
|
|
20
|
+
- [LinkedIn](#linkedin)
|
|
21
|
+
- [Mastodon](#mastodon)
|
|
20
22
|
- [Microlink](#microlink)
|
|
21
23
|
- [OnlyFans](#onlyfans)
|
|
22
24
|
- [OpenStreetMap](#openstreetmap)
|
|
@@ -223,6 +225,20 @@ It resolves user avatar against **instagram.com**.
|
|
|
223
225
|
|
|
224
226
|
e.g., [unavatar.io/instagram/willsmith](https://unavatar.io/instagram/willsmith)
|
|
225
227
|
|
|
228
|
+
### LinkedIn
|
|
229
|
+
|
|
230
|
+
It resolves user avatar against **linkedin.com**.
|
|
231
|
+
|
|
232
|
+
e.g., [unavatar.io/linkedin/kikobeats](https://unavatar.io/linkedin/kikobeats)
|
|
233
|
+
|
|
234
|
+
### Mastodon
|
|
235
|
+
|
|
236
|
+
It resolves user avatar from any **Mastodon** instance using the public account lookup API.
|
|
237
|
+
|
|
238
|
+
Because Mastodon is federated, the input must include both the username and the server. The following formats are supported:
|
|
239
|
+
|
|
240
|
+
- `user@server`: [unavatar.io/mastodon/kpwags@hachyderm.io](https://unavatar.io/mastodon/kpwags@hachyderm.io)
|
|
241
|
+
|
|
226
242
|
### Microlink
|
|
227
243
|
|
|
228
244
|
It resolves user avatar using **microlink.io**.
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@unavatar/core",
|
|
3
3
|
"description": "Get unified user avatar from social networks, including Instagram, SoundCloud, Telegram, Twitter, YouTube & more.",
|
|
4
4
|
"homepage": "https://unavatar.io",
|
|
5
|
-
"version": "3.7.
|
|
5
|
+
"version": "3.7.63",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": "./src/index.js",
|
|
@@ -34,6 +34,10 @@
|
|
|
34
34
|
"name": "Alexander Schlindwein",
|
|
35
35
|
"email": "alexander.schlindwein@hotmail.de"
|
|
36
36
|
},
|
|
37
|
+
{
|
|
38
|
+
"name": "Wes Bos",
|
|
39
|
+
"email": "wesbos@gmail.com"
|
|
40
|
+
},
|
|
37
41
|
{
|
|
38
42
|
"name": "Zadkiel",
|
|
39
43
|
"email": "hello@zadkiel.fr"
|
|
@@ -134,7 +138,7 @@
|
|
|
134
138
|
"p-any": "~3.0.0",
|
|
135
139
|
"p-cancelable": "2.1.1",
|
|
136
140
|
"p-timeout": "~4.1.0",
|
|
137
|
-
"puppeteer": "~24.
|
|
141
|
+
"puppeteer": "~24.40.0",
|
|
138
142
|
"re2": "~1.23.3",
|
|
139
143
|
"srcset": "~4.0.0",
|
|
140
144
|
"stable-regex": "~1.0.0",
|
package/src/index.js
CHANGED
|
@@ -15,6 +15,7 @@ module.exports = ({ constants: userConstants, redis, onFetchHTML } = {}) => {
|
|
|
15
15
|
const { createMultiCache, createRedisCache } = require('./util/keyv')({ ...constants, redis })
|
|
16
16
|
const cache = require('./util/cache')({ createMultiCache, createRedisCache })
|
|
17
17
|
const cacheableLookup = require('./util/cacheable-lookup')({ ...constants, cache: cache.dnsCache })
|
|
18
|
+
const isReservedIp = require('./util/is-reserved-ip')({ cacheableLookup })
|
|
18
19
|
const got = require('./util/got')({ cacheableLookup })
|
|
19
20
|
const reachableUrl = require('./util/reachable-url')({ got, pingCache: cache.pingCache })
|
|
20
21
|
const createBrowser = require('./util/browserless')(constants)
|
|
@@ -25,7 +26,14 @@ module.exports = ({ constants: userConstants, redis, onFetchHTML } = {}) => {
|
|
|
25
26
|
onFetchHTML
|
|
26
27
|
})
|
|
27
28
|
|
|
28
|
-
const providerCtx = {
|
|
29
|
+
const providerCtx = {
|
|
30
|
+
constants,
|
|
31
|
+
createHtmlProvider,
|
|
32
|
+
getOgImage,
|
|
33
|
+
got,
|
|
34
|
+
isReservedIp,
|
|
35
|
+
itunesSearchCache: cache.itunesSearchCache
|
|
36
|
+
}
|
|
29
37
|
const { providers, providersBy } = require('./providers')(providerCtx)
|
|
30
38
|
|
|
31
39
|
const { auto, getInputType, getAvatar } = require('./avatar/auto')({
|
package/src/providers/index.js
CHANGED
|
@@ -10,6 +10,8 @@ const providersBy = {
|
|
|
10
10
|
'github',
|
|
11
11
|
'gitlab',
|
|
12
12
|
'instagram',
|
|
13
|
+
'linkedin',
|
|
14
|
+
'mastodon',
|
|
13
15
|
'onlyfans',
|
|
14
16
|
'openstreetmap',
|
|
15
17
|
'patreon',
|
|
@@ -39,6 +41,8 @@ module.exports = ctx => {
|
|
|
39
41
|
google: require('./google')(ctx),
|
|
40
42
|
gravatar: require('./gravatar')(ctx),
|
|
41
43
|
instagram: require('./instagram')(ctx),
|
|
44
|
+
linkedin: require('./linkedin')(ctx),
|
|
45
|
+
mastodon: require('./mastodon')(ctx),
|
|
42
46
|
microlink: require('./microlink')(ctx),
|
|
43
47
|
onlyfans: require('./onlyfans')(ctx),
|
|
44
48
|
openstreetmap: require('./openstreetmap')(ctx),
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const isValidServer = server => {
|
|
4
|
+
try {
|
|
5
|
+
const url = new URL(`https://${server}`)
|
|
6
|
+
return (
|
|
7
|
+
Boolean(url.hostname) &&
|
|
8
|
+
url.username === '' &&
|
|
9
|
+
url.password === '' &&
|
|
10
|
+
url.pathname === '/' &&
|
|
11
|
+
url.search === '' &&
|
|
12
|
+
url.hash === '' &&
|
|
13
|
+
url.host.toLowerCase() === server.toLowerCase()
|
|
14
|
+
)
|
|
15
|
+
} catch {
|
|
16
|
+
return false
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const parseMastodonInput = input => {
|
|
21
|
+
if (typeof input !== 'string') return null
|
|
22
|
+
|
|
23
|
+
const cleaned = input.startsWith('@') ? input.slice(1) : input
|
|
24
|
+
const parts = cleaned.split('@')
|
|
25
|
+
if (parts.length !== 2) return null
|
|
26
|
+
|
|
27
|
+
const [username, server] = parts
|
|
28
|
+
if (!username || !server) return null
|
|
29
|
+
if (!isValidServer(server)) return null
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
username,
|
|
33
|
+
server
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = ({ got, isReservedIp }) => {
|
|
38
|
+
const mastodon = async function ({ input }) {
|
|
39
|
+
const parsed = parseMastodonInput(input)
|
|
40
|
+
if (!parsed) return undefined
|
|
41
|
+
|
|
42
|
+
const { username, server } = parsed
|
|
43
|
+
|
|
44
|
+
if (await isReservedIp(server)) return undefined
|
|
45
|
+
|
|
46
|
+
const { body } = await got(
|
|
47
|
+
`https://${server}/api/v1/accounts/lookup?acct=${encodeURIComponent(
|
|
48
|
+
username
|
|
49
|
+
)}`,
|
|
50
|
+
{ responseType: 'json' }
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
return body?.avatar
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
mastodon.parseMastodonInput = parseMastodonInput
|
|
57
|
+
return mastodon
|
|
58
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const ip = require('ipaddr.js')
|
|
4
|
+
|
|
5
|
+
module.exports = ({ cacheableLookup }) => {
|
|
6
|
+
const getIpAddress = async hostname => {
|
|
7
|
+
if (ip.IPv4.isIPv4(hostname)) return hostname
|
|
8
|
+
if (
|
|
9
|
+
hostname.startsWith('[') &&
|
|
10
|
+
hostname.endsWith(']') &&
|
|
11
|
+
ip.IPv6.isIPv6(hostname.slice(1, -1))
|
|
12
|
+
) {
|
|
13
|
+
return hostname.slice(1, -1)
|
|
14
|
+
}
|
|
15
|
+
const { address } = await cacheableLookup.lookupAsync(hostname)
|
|
16
|
+
return address
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return async hostname => {
|
|
20
|
+
const ipAddress = await getIpAddress(hostname)
|
|
21
|
+
return ip.process(ipAddress).range() !== 'unicast'
|
|
22
|
+
}
|
|
23
|
+
}
|