fluidtrends/carmel.sdk

View on GitHub
src/auth/GitHubProvider.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { Strategy } from 'passport-github2'
import passport from 'passport'
import { Octokit } from '@octokit/rest'
import { createTokenAuth } from '@octokit/auth-token'

import {
  Authenticator,
  IRepo,
  IAuthKey,
  User,
  IAuthProvider,
  AccessTokenType,
} from '..'

/**
 *
 */
export class GitHubProvider implements IAuthProvider {
  /** */
  public static APP_CLIENT_ID = '638343cb36c073a0a29f'

  /** */
  public static APP_CLIENT_SECRET = '7008e0bf5922f1b2cea61e2d62e4b6057288b367'

  /** @internal */
  protected _authenticator: Authenticator

  /** @internal */
  protected _keys: IAuthKey[]

  /**
   *
   * @param authenticator
   */
  constructor(authenticator: Authenticator) {
    this._authenticator = authenticator
    this._keys = []
  }

  /**
   *
   */
  get keys() {
    return this._keys
  }

  /**
   *
   */
  get authenticator() {
    return this._authenticator
  }

  /**
   *
   */
  get token() {
    return this.authenticator.session.token(AccessTokenType.GITHUB)
  }

  /**
   *
   */
  get isLoggedIn() {
    return this.token !== undefined
  }

  /**
   *
   * @param uri
   * @param options
   * @param patch
   */
  async request(uri: string, options?: any, patch?: boolean) {
    if (!this.isLoggedIn) return
  }

  /**
   *
   * @param name
   * @param repo
   */
  async push(name: string, repo: IRepo) {
    if (!this.isLoggedIn) return
  }

  /**
   *
   */
  async setupNewKey(title: string, service?: any) {
    // Looks like we have no github keys stored, let's create one
    const newLocalKey = await this.authenticator.session.keystore.addNewKey(
      'github'
    )

    // And add it remotely
    await service.users.createPublicSshKeyForAuthenticated({
      title,
      key: newLocalKey.files.get('public.ssh')?.data.raw,
    })

    // Keep track of it
    this._keys.push(newLocalKey)

    return newLocalKey
  }

  /**
   *
   * @param service
   */
  async fetchRemoteKeys(service?: any) {
    const { data } = await service.users.listPublicSshKeysForAuthenticated()

    return data
  }

  /**
   *
   */
  async prepareKeys() {
    if (!this.authenticator.session.isLoggedIn) {
      return
    }

    const { keystore, system } = this.authenticator.session
    const service = new Octokit({
      auth: this.authenticator.session.token(AccessTokenType.GITHUB),
    })

    // Let's look up local and remote keys
    const localKeys: IAuthKey[] = keystore.keys.get('github') || []
    const remoteKeys = (await this.fetchRemoteKeys(service)) || []

    let title = `carmel/${system?.id}`

    if (localKeys.length === 0) {
      await this.setupNewKey(`${title}/0`, service)
      return
    }

    // Look for key matches
    let foundTitles: string[] = []
    remoteKeys.map((remoteKey: any) => {
      localKeys.map((localKey) => {
        const ssh = localKey.files.get('public.ssh')?.data.raw
        ssh === `${remoteKey.key} carmel` && this.keys.push(localKey)
        remoteKey.title.startsWith(title) &&
          foundTitles.push(remoteKey.title.substring(title.length + 1) || '0')
      })
    })

    // Calculate the next unique title
    foundTitles = foundTitles.map((suffix: string) => `${suffix}`)
    const subId = Array.from(Array(100).keys()).find(
      (id) => !foundTitles.includes(`${id + 1}`)
    )
    title = `${title}/${subId! + 1}`

    this.keys.length > 0 || (await this.setupNewKey(title, service))
  }

  async initialize() {
    // passport.serializeUser((user: User, done: any) => {
    //   done(null, user)
    // })

    // passport.deserializeUser((user: User, done) => {
    //   done(null, user)
    // })

    // passport.use(
    //   new Strategy(
    //     {
    //       clientID: GitHubProvider.APP_CLIENT_ID,
    //       clientSecret: GitHubProvider.APP_CLIENT_SECRET,
    //       callbackURL: this.authenticator.endpoint(`auth/github/callback`),
    //     },
    //     (accessToken: any, refreshToken: any, profile: any, done: any) => {
    //       process.nextTick(() => {
    //         const user = {
    //           ...profile._json,
    //           tokens: [
    //             {
    //               type: AccessTokenType.GITHUB,
    //               value: accessToken,
    //             },
    //           ],
    //         }
    //         this.authenticator.update(user)
    //         done(null, user)
    //       })
    //     }
    //   )
    // )

    // this.authenticator.app.get(
    //   '/auth/github',
    //   passport.authenticate('github', {
    //     scope: ['user:email', 'write:public_key'],
    //   })
    // )

    // this.authenticator.app.get(
    //   '/auth/github/callback',
    //   passport.authenticate('github', {
    //     failureRedirect: '/login',
    //   }),
    //   (req, res) => {
    //     res.redirect('/auth/vercel')
    //   }
    // )
  }
}