import generator , { ProxyConfig } from 'megalodon' ; import crypto from 'crypto' ; import Account from './account' ; import { LocalAccount } from '~/src/types/localAccount' ; const appName = 'Whalebird' ; const appURL = 'https://whalebird.org' ; export default class Authentication { private db : Account ; private baseURL : string | null = null ; private domain : string | null = null ; private clientId : string | null = null ; private clientSecret : string | null = null ; private sessionToken : string | null = null ; private protocol : 'http' | 'https' ; constructor ( accountDB ) { this . db = accountDB ; this . protocol = 'https' ; } setOtherInstance ( domain ) { this . baseURL = `${ this . protocol }://${ domain }` ; this . domain = domain ; this . clientId = null ; this . clientSecret = null ; } async getAuthorizationUrl ( sns , domain = 'mastodon.social' , proxy ) { this . setOtherInstance ( domain ) ; if ( ! this . baseURL || ! this . domain ) { throw new Error ( 'domain is required' ) ; } const client = generator ( sns , this . baseURL , null , 'Whalebird' , proxy ) ; const res = await client . registerApp ( appName , { website : appURL } ) ; this . clientId = res . clientId ; this . clientSecret = res . clientSecret ; this . sessionToken = res . session_token ; const order = await this . db . lastAccount ( ) . then ( account => account . order + 1 ) . catch ( err => { console . log ( err ) ; return 1 ; } ) ; const local = { baseURL : this . baseURL , domain : this . domain , clientId : this . clientId , clientSecret : this . clientSecret , accessToken : null , refreshToken : null , username : null , accountId : null , avatar : null , order : order } ; await this . db . insertAccount ( local ) ; if ( res . url === null ) { throw new AuthenticationURLError ( 'Can not get url' ) ; } return res . url ; } async getAndUpdateAccessToken ( sns , code , proxy ) { if ( ! this . baseURL ) { throw new Error ( 'domain is required' ) ; } if ( ! this . clientSecret ) { throw new Error ( 'client secret is required' ) ; } const client = generator ( sns , this . baseURL , null , 'Whalebird' , proxy ) ; let authCode = code ; if ( ! code ) { authCode = this . sessionToken ; } if ( ! authCode ) { throw new Error ( 'auth code is required' ) ; } const tokenData = await client . fetchAccessToken ( this . clientId , this . clientSecret , authCode , 'urn:ietf:wg:oauth:2.0:oob' ) ; const search = { baseURL : this . baseURL , domain : this . domain , clientId : this . clientId , clientSecret : this . clientSecret } ; const rec = await this . db . searchAccount ( search ) ; let accessToken = tokenData . accessToken ; if ( sns === 'misskey' ) { accessToken = crypto . createHash ( 'sha256' ) . update ( tokenData . accessToken + this . clientSecret , 'utf8' ) . digest ( 'hex' ) ; } const refreshToken = tokenData . refreshToken ; const data = await this . db . fetchAccount ( sns , rec , accessToken , proxy ) ; await this . db . updateAccount ( rec . _id ! , { username : data . username , accountId : data . id , avatar : data . avatar , accessToken : accessToken , refreshToken : refreshToken } ) ; return accessToken ; } } class AuthenticationURLError extends Error { }