Skip to content

Instantly share code, notes, and snippets.

@iseebi
Created January 9, 2020 13:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iseebi/4d21bf68c79bc020ea3515693676a35f to your computer and use it in GitHub Desktop.
Save iseebi/4d21bf68c79bc020ea3515693676a35f to your computer and use it in GitHub Desktop.
コマンドラインでGoogle APIのOAuthを通すクラス
/* tslint:disable:no-console */
import * as fs from "fs";
import {Credentials, OAuth2Client} from "google-auth-library"
import {google} from "googleapis";
import * as path from "path";
import {createInterface} from "readline";
import {ReadLine} from "readline";
interface IClientID {
client_id: string
client_secret: string
}
interface IClientIDFile {
installed: IClientID
}
const CALLBACK_URL = 'urn:ietf:wg:oauth:2.0:oob';
export class Authenticator {
private readonly baseDir: string;
private readonly scopes: string[];
private readonly tokenFileName: string;
private readonly clientIdFileName: string;
private oAuth2Client?: OAuth2Client;
private readline?: ReadLine;
constructor(baseDir: string, scopes: string[]) {
this.baseDir = baseDir;
this.scopes = scopes;
this.tokenFileName = path.join(this.baseDir, 'token.json');
this.clientIdFileName = path.join(this.baseDir, 'client_id.json');
}
public async authenticateAsync(): Promise<OAuth2Client> {
let token = await this.readTokenAsync();
if (!token) {
token = await this.getNewTokenAsync();
}
const client = await this.getClientAsync();
client.setCredentials(token);
return client;
}
private async getClientAsync(): Promise<OAuth2Client> {
if (!this.oAuth2Client) {
const clientIdFile = await this.readClientIdAsync();
const clientId = clientIdFile.installed;
this.oAuth2Client = new google.auth.OAuth2(clientId.client_id, clientId.client_secret, CALLBACK_URL);
}
return this.oAuth2Client;
}
private async getNewTokenAsync(): Promise<Credentials> {
const client = await this.getClientAsync();
const authUrl = client.generateAuthUrl({
access_type: 'offline',
scope: this.scopes
});
console.log('Authorize this app by visiting this url: ', authUrl);
const code = await this.askAsync('Enter the code from that page here: ');
const token = await client.getToken(code);
await this.writeTokenAsync(token.tokens);
return token.tokens;
}
private async readClientIdAsync(): Promise<IClientIDFile> {
const file = await fs.promises.readFile(this.clientIdFileName, {encoding: "utf8"});
return JSON.parse(file);
}
private async writeTokenAsync(token: Credentials): Promise<void> {
await fs.promises.writeFile(this.tokenFileName, JSON.stringify(token));
}
private async readTokenAsync(): Promise<Credentials|undefined> {
try {
await fs.promises.stat(this.tokenFileName);
const file = await fs.promises.readFile(this.tokenFileName, {encoding: "utf8"});
return JSON.parse(file);
}
catch(e) {
return undefined;
}
}
private getReadLine(): ReadLine {
if (!this.readline) {
this.readline = createInterface({
input: process.stdin,
output: process.stdout,
});
}
return this.readline;
}
private askAsync(query: string): Promise<string> {
const rl = this.getReadLine();
return new Promise((resolve) => {
rl.question(query, (input) => {
rl.close();
resolve(input)
});
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment