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
130
|
/**
* Fetch the Mojang username API through api.ashcon.app
*/
import fetch from 'node-fetch'
import * as nodeFetch from 'node-fetch'
import { Agent } from 'https'
import { isUuid, undashUuid } from './util'
// We need to create an agent to prevent memory leaks
const httpsAgent = new Agent({
keepAlive: true
})
interface MojangApiResponse {
/** These uuids are already undashed */
uuid: string
username: string
}
/**
* Get mojang api data from the session server
*/
export async function profileFromUuid(uuid: string): Promise<MojangApiResponse> {
let fetchResponse: nodeFetch.Response
try {
fetchResponse = await fetch(
// using mojang directly is faster than ashcon lol, also mojang removed the ratelimits from here
`https://sessionserver.mojang.com/session/minecraft/profile/${undashUuid(uuid)}`,
{ agent: () => httpsAgent }
)
} catch {
// if there's an error, wait a second and try again
await new Promise((resolve) => setTimeout(resolve, 1000))
return await profileFromUuid(uuid)
}
let dataString: string
try {
dataString = await fetchResponse.text()
} catch {
return { uuid: null, username: null }
}
let data
try {
data = JSON.parse(dataString)
} catch {
console.log('mojang response:', dataString)
// if it errors, just return null
return { uuid: null, username: null }
}
if (!data.id)
console.log('mojang response:', data)
return {
uuid: data.id,
username: data.name
}
}
export async function profileFromUsername(username: string): Promise<MojangApiResponse> {
// since we don't care about anything other than the uuid, we can use /uuid/ instead of /user/
let fetchResponse: nodeFetch.Response
try {
fetchResponse = await fetch(
`https://api.mojang.com/users/profiles/minecraft/${username}`,
{ agent: () => httpsAgent }
)
} catch {
// if there's an error, wait a second and try again
await new Promise((resolve) => setTimeout(resolve, 1000))
return await profileFromUsername(username)
}
let data = null
const rawData = await fetchResponse.text()
try {
data = JSON.parse(rawData)
} catch {}
if (!data?.id) {
console.log('no id returned from mojang', rawData)
// return { uuid: null, username: null }
return await profileFromUsernameAlternative(username)
}
return {
uuid: data.id,
username: data.name
}
}
export async function profileFromUsernameAlternative(username: string): Promise<MojangApiResponse> {
let fetchResponse: nodeFetch.Response
try {
fetchResponse = await fetch(
`https://api.ashcon.app/mojang/v2/user/${username}`,
{ agent: () => httpsAgent }
)
} catch {
// if there's an error, wait a second and try again
await new Promise((resolve) => setTimeout(resolve, 1000))
return await profileFromUsernameAlternative(username)
}
let data
try {
data = await fetchResponse.json()
} catch {
return { uuid: null, username: null }
}
if (!data.uuid)
return { uuid: null, username: null }
return {
uuid: undashUuid(data.uuid),
username: data.username
}
}
export async function profileFromUser(user: string): Promise<MojangApiResponse> {
if (isUuid(user)) {
return await profileFromUuid(user)
} else
return await profileFromUsername(user)
}
|