增加检查discord role的接口
This commit is contained in:
parent
dba4eddee7
commit
2bf81f8e1c
@ -1,8 +0,0 @@
|
|||||||
.idea
|
|
||||||
node_modules
|
|
||||||
build
|
|
||||||
dist
|
|
||||||
.DS_Store
|
|
||||||
tmp
|
|
||||||
target
|
|
||||||
boundle.log
|
|
@ -23,7 +23,7 @@ class DiscordController extends BaseController {
|
|||||||
record.refreshToken = tokenResponse.refresh_token
|
record.refreshToken = tokenResponse.refresh_token
|
||||||
record.scope = tokenResponse.scope
|
record.scope = tokenResponse.scope
|
||||||
record.tokenType = tokenResponse.token_type
|
record.tokenType = tokenResponse.token_type
|
||||||
record.expiresIn = tokenResponse.expires_in || 0 + Date.now()
|
record.expiresIn = (Date.now() / 1000 + tokenResponse.expires_in) | 0
|
||||||
await record.save()
|
await record.save()
|
||||||
if (tokenResponse && tokenResponse.access_token) {
|
if (tokenResponse && tokenResponse.access_token) {
|
||||||
let uinfo = await userInfo(tokenResponse.access_token)
|
let uinfo = await userInfo(tokenResponse.access_token)
|
||||||
|
@ -3,11 +3,12 @@ import { ZError } from 'common/ZError'
|
|||||||
import { role, router } from 'decorators/router'
|
import { role, router } from 'decorators/router'
|
||||||
import logger from 'logger/logger'
|
import logger from 'logger/logger'
|
||||||
import { AuthRecord, PlatEnum } from 'modules/AuthRecord'
|
import { AuthRecord, PlatEnum } from 'modules/AuthRecord'
|
||||||
import { DiscordSvr } from 'services/discord.svr'
|
import { DiscordSvr, getAvableAccessToken, userGuildMember } from 'services/discord.svr'
|
||||||
import { hmacsha256 } from 'utils/security.util'
|
import { hmacsha256 } from 'utils/security.util'
|
||||||
|
|
||||||
const checkSign = (params: { address?: string; sign?: string }) => {
|
const checkSign = (params: { address?: string; sign?: string }) => {
|
||||||
const { address, sign } = params
|
let { address, sign } = params
|
||||||
|
address = address.toLowerCase()
|
||||||
if (!address || !sign) {
|
if (!address || !sign) {
|
||||||
throw new ZError(10, 'invalid params')
|
throw new ZError(10, 'invalid params')
|
||||||
}
|
}
|
||||||
@ -119,21 +120,49 @@ class MainController extends BaseController {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否加入某guid
|
||||||
|
*/
|
||||||
@role(ROLE_ANON)
|
@role(ROLE_ANON)
|
||||||
@router('get /activity/discord/svr/:id')
|
@router('post /activity/discord/guild')
|
||||||
async checkDiscordJoin(req) {
|
async checkDiscordJoin(req) {
|
||||||
let { id } = req.params
|
let { gid, address } = req.params
|
||||||
checkSign(req.params)
|
checkSign(req.params)
|
||||||
let verified = new DiscordSvr().checkUser(id)
|
address = address.toLowerCase()
|
||||||
return { verified }
|
let record = await AuthRecord.findOne({ address, platform: PlatEnum.DISCORD })
|
||||||
|
if (!record) {
|
||||||
|
throw new ZError(12, 'not found discord record')
|
||||||
|
}
|
||||||
|
let accessToken = await getAvableAccessToken(record)
|
||||||
|
// TODO:: check local cache
|
||||||
|
let data = await userGuildMember(accessToken, gid)
|
||||||
|
if (!data || data.code) {
|
||||||
|
throw new ZError(13, 'not found guild')
|
||||||
|
}
|
||||||
|
return { result: true }
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 检查是否有某个role
|
||||||
|
*/
|
||||||
@role(ROLE_ANON)
|
@role(ROLE_ANON)
|
||||||
@router('get /activity/discord/role/:id')
|
@router('post /activity/discord/role')
|
||||||
async checkDiscordRole(req) {
|
async checkDiscordRole(req) {
|
||||||
let { id } = req.params
|
let { rid, gid, address } = req.params
|
||||||
checkSign(req.params)
|
checkSign(req.params)
|
||||||
let verified = new DiscordSvr().checkUserRole(id)
|
address = address.toLowerCase()
|
||||||
return { verified }
|
let record = await AuthRecord.findOne({ address, platform: PlatEnum.DISCORD })
|
||||||
|
if (!record) {
|
||||||
|
throw new ZError(12, 'not found discord record')
|
||||||
|
}
|
||||||
|
let accessToken = await getAvableAccessToken(record)
|
||||||
|
console.log('discord access token:', accessToken)
|
||||||
|
// TODO:: check local cache
|
||||||
|
let data = await userGuildMember(accessToken, gid)
|
||||||
|
console.log(data?.roles)
|
||||||
|
if (!data || data.code) {
|
||||||
|
throw new ZError(13, 'not found guild')
|
||||||
|
}
|
||||||
|
let roleSet = new Set(data.roles)
|
||||||
|
return { result: roleSet.has(rid) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ class TwitterController extends BaseController {
|
|||||||
record.refreshToken = tokenResponse.refresh_token
|
record.refreshToken = tokenResponse.refresh_token
|
||||||
record.scope = tokenResponse.scope
|
record.scope = tokenResponse.scope
|
||||||
record.tokenType = tokenResponse.token_type
|
record.tokenType = tokenResponse.token_type
|
||||||
record.expiresIn = tokenResponse.expires_in || 0 + Date.now()
|
record.expiresIn = (Date.now() / 1000 + tokenResponse.expires_in || 0) | 0
|
||||||
await record.save()
|
await record.save()
|
||||||
if (tokenResponse && tokenResponse.access_token) {
|
if (tokenResponse && tokenResponse.access_token) {
|
||||||
const uinfo = await getTwitterUserInfo(tokenResponse.access_token)
|
const uinfo = await getTwitterUserInfo(tokenResponse.access_token)
|
||||||
|
@ -2,6 +2,11 @@ import { ZError } from 'common/ZError'
|
|||||||
import { singleton } from 'decorators/singleton'
|
import { singleton } from 'decorators/singleton'
|
||||||
|
|
||||||
import { Client, Events, GatewayIntentBits, Guild } from 'discord.js'
|
import { Client, Events, GatewayIntentBits, Guild } from 'discord.js'
|
||||||
|
import { AuthRecordClass } from 'modules/AuthRecord'
|
||||||
|
import { DocumentType } from '@typegoose/typegoose'
|
||||||
|
|
||||||
|
const DISCORD_API_HOST = 'https://discord.com/api/v10'
|
||||||
|
const DISCORD_APP_HOST = 'https://discordapp.com/api'
|
||||||
|
|
||||||
export async function exchangeDiscrodCodeForToken(code: string) {
|
export async function exchangeDiscrodCodeForToken(code: string) {
|
||||||
const clientId = process.env.DISCORD_CLIENT_ID
|
const clientId = process.env.DISCORD_CLIENT_ID
|
||||||
@ -19,7 +24,6 @@ export async function exchangeDiscrodCodeForToken(code: string) {
|
|||||||
client_secret: clientSecret,
|
client_secret: clientSecret,
|
||||||
redirect_uri: redirectUri,
|
redirect_uri: redirectUri,
|
||||||
code,
|
code,
|
||||||
scope: 'identify email',
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -27,15 +31,102 @@ export async function exchangeDiscrodCodeForToken(code: string) {
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getAvableAccessToken(record: DocumentType<AuthRecordClass>) {
|
||||||
|
if (record.expiresIn < Date.now() / 1000 + 60 * 5) {
|
||||||
|
console.log('discord access token expired')
|
||||||
|
const data = await refreshDiscordToken(record.refreshToken)
|
||||||
|
if (data.code) {
|
||||||
|
throw new ZError(10, 'refresh token error')
|
||||||
|
}
|
||||||
|
record.accessToken = data.access_token
|
||||||
|
record.refreshToken = data.refresh_token
|
||||||
|
record.expiresIn = (Date.now() / 1000 + data.expires_in || 0) | 0
|
||||||
|
await record.save()
|
||||||
|
}
|
||||||
|
return record.accessToken
|
||||||
|
}
|
||||||
|
export async function refreshDiscordToken(rtoken: string) {
|
||||||
|
const clientId = process.env.DISCORD_CLIENT_ID
|
||||||
|
const clientSecret = process.env.DISCORD_CLIENT_SECRET
|
||||||
|
const response = await fetch('https://discord.com/api/oauth2/token', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
body: new URLSearchParams({
|
||||||
|
grant_type: 'refresh_token',
|
||||||
|
client_id: clientId,
|
||||||
|
client_secret: clientSecret,
|
||||||
|
refresh_token: rtoken,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
const data = await response.json()
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 用户基本信息
|
||||||
|
* @param token
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
export async function userInfo(token: string) {
|
export async function userInfo(token: string) {
|
||||||
const response = await fetch('https://discord.com/api/users/@me', {
|
const response = await fetch(`${DISCORD_APP_HOST}/users/@me`, {
|
||||||
headers: {
|
headers: {
|
||||||
authorization: `Bearer ${token}`,
|
authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
console.log(data)
|
return data
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 用户所在的工会列表, oauth2方式
|
||||||
|
* @param token
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export async function userGuildList(token: string) {
|
||||||
|
const url = `${DISCORD_APP_HOST}/users/@me/guilds`
|
||||||
|
const response = await fetch(url, {
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const data = await response.json()
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户在某个工会的信息, oauth2方式
|
||||||
|
* @param token
|
||||||
|
* @param guildId
|
||||||
|
* @returns
|
||||||
|
* 返回的数据结构:
|
||||||
|
* https://discord.com/developers/docs/resources/guild#guild-member-object
|
||||||
|
*/
|
||||||
|
export async function userGuildMember(token: string, guildId: string) {
|
||||||
|
const url = `${DISCORD_APP_HOST}/users/@me/guilds/${guildId}/member`
|
||||||
|
const response = await fetch(url, {
|
||||||
|
headers: {
|
||||||
|
authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const data = await response.json()
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 直接通过discord接口, 获取工会中某用户信息
|
||||||
|
* 返回的数据结构:
|
||||||
|
* https://discord.com/developers/docs/resources/guild#guild-member-object
|
||||||
|
*/
|
||||||
|
export async function getGuildMember(uid: string) {
|
||||||
|
const url = `${DISCORD_API_HOST}/guilds/${process.env.DISCROD_GUILD_ID}/members/${uid}`
|
||||||
|
const token = process.env.DISCORD_BOT_TOKEN
|
||||||
|
const response = await fetch(url, {
|
||||||
|
headers: {
|
||||||
|
authorization: `Bot ${token}`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const data = await response.json()
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user