github-profile-status
Advanced tools
Comparing version 0.1.0 to 0.2.0
import { Emoji } from './Emoji'; | ||
interface StatusUpdaterConstructorOptions { | ||
session: string; | ||
} | ||
import { BasicLoginOptions } from './login/BasicLoginProvider'; | ||
import { SessionLoginOptions } from './login/SessionLoginProvider'; | ||
interface Status { | ||
@@ -10,6 +9,10 @@ message: string; | ||
} | ||
interface ConstructorOptions { | ||
debug?: boolean; | ||
} | ||
export declare class GithubProfileStatus { | ||
private options; | ||
private loginProvider; | ||
constructor(options: StatusUpdaterConstructorOptions); | ||
constructor(options: ConstructorOptions & BasicLoginOptions); | ||
constructor(options: ConstructorOptions & SessionLoginOptions); | ||
/** | ||
@@ -16,0 +19,0 @@ * Gets the current user profile status |
@@ -38,2 +38,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var BasicLoginProvider_1 = require("./login/BasicLoginProvider"); | ||
var SessionLoginProvider_1 = require("./login/SessionLoginProvider"); | ||
@@ -43,6 +44,11 @@ var GithubProfileStatus = /** @class */ (function () { | ||
this.options = options; | ||
if (typeof options.session !== 'string') { | ||
throw new Error('You must provide a user session cookie'); | ||
if (SessionLoginProvider_1.SessionLoginProvider.validateOptions(options)) { | ||
this.loginProvider = new SessionLoginProvider_1.SessionLoginProvider(options); | ||
} | ||
this.loginProvider = new SessionLoginProvider_1.SessionLoginProvider(options.session); | ||
else if (BasicLoginProvider_1.BasicLoginProvider.validateOptions(options)) { | ||
this.loginProvider = new BasicLoginProvider_1.BasicLoginProvider(options); | ||
} | ||
else { | ||
throw new Error('Invalid login options'); | ||
} | ||
} | ||
@@ -116,5 +122,3 @@ /** | ||
_a.sent(); | ||
return [4 /*yield*/, homePage.waitForResponse(function (response) { | ||
return response.url().includes('/users/status') && response.status() === 200; | ||
})]; | ||
return [4 /*yield*/, homePage.waitForResponse(function (response) { return response.url().includes('/users/status') && response.status() === 200; })]; | ||
case 8: | ||
@@ -121,0 +125,0 @@ _a.sent(); |
@@ -1,4 +0,8 @@ | ||
import { Page } from 'puppeteer'; | ||
export declare abstract class LoginProvider { | ||
login(): Promise<Page>; | ||
import puppeteer from 'puppeteer'; | ||
export declare abstract class LoginProvider<T> { | ||
protected options: T; | ||
static validateOptions(options: any): boolean; | ||
constructor(options: T); | ||
login(): Promise<puppeteer.Page>; | ||
protected createPage(options?: puppeteer.LaunchOptions): Promise<puppeteer.Page>; | ||
} |
@@ -37,6 +37,14 @@ "use strict"; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var puppeteer_1 = __importDefault(require("puppeteer")); | ||
var LoginProvider = /** @class */ (function () { | ||
function LoginProvider() { | ||
function LoginProvider(options) { | ||
this.options = options; | ||
} | ||
LoginProvider.validateOptions = function (options) { | ||
throw new Error('Method no implemented'); | ||
}; | ||
LoginProvider.prototype.login = function () { | ||
@@ -49,4 +57,34 @@ return __awaiter(this, void 0, void 0, function () { | ||
}; | ||
LoginProvider.prototype.createPage = function (options) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var browser, page; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, puppeteer_1.default.launch(options)]; | ||
case 1: | ||
browser = _a.sent(); | ||
return [4 /*yield*/, browser.newPage()]; | ||
case 2: | ||
page = _a.sent(); | ||
return [4 /*yield*/, page.setRequestInterception(true)]; | ||
case 3: | ||
_a.sent(); | ||
page.on('request', function (request) { | ||
if (request.resourceType() === 'document') { | ||
request.continue(); | ||
} | ||
else if (request.resourceType() === 'script' && request.url().includes('frameworks')) { | ||
request.continue(); | ||
} | ||
else { | ||
request.abort(); | ||
} | ||
}); | ||
return [2 /*return*/, page]; | ||
} | ||
}); | ||
}); | ||
}; | ||
return LoginProvider; | ||
}()); | ||
exports.LoginProvider = LoginProvider; |
import puppeteer from 'puppeteer'; | ||
import { LoginProvider } from './LoginProvider'; | ||
export declare class SessionLoginProvider implements LoginProvider { | ||
private userSession; | ||
constructor(userSession: string); | ||
export interface SessionLoginOptions { | ||
sessionCookie: string; | ||
} | ||
export declare class SessionLoginProvider extends LoginProvider<SessionLoginOptions> { | ||
static validateOptions(options: any): options is SessionLoginOptions; | ||
login(): Promise<puppeteer.Page>; | ||
} |
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
return function (d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
@@ -37,54 +50,38 @@ return new (P || (P = Promise))(function (resolve, reject) { | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var puppeteer_1 = __importDefault(require("puppeteer")); | ||
var LoginProvider_1 = require("./LoginProvider"); | ||
var GITHUB_URL = 'https://github.com/'; | ||
var SessionLoginProvider = /** @class */ (function () { | ||
function SessionLoginProvider(userSession) { | ||
this.userSession = userSession; | ||
var SessionLoginProvider = /** @class */ (function (_super) { | ||
__extends(SessionLoginProvider, _super); | ||
function SessionLoginProvider() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
SessionLoginProvider.validateOptions = function (options) { | ||
return typeof options.sessionCookie === 'string'; | ||
}; | ||
SessionLoginProvider.prototype.login = function () { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var browser, page, _i, _a, cookie; | ||
var page, _i, _a, cookie; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: return [4 /*yield*/, puppeteer_1.default.launch()]; | ||
case 0: return [4 /*yield*/, this.createPage()]; | ||
case 1: | ||
browser = _b.sent(); | ||
return [4 /*yield*/, browser.newPage()]; | ||
case 2: | ||
page = _b.sent(); | ||
return [4 /*yield*/, page.setRequestInterception(true)]; | ||
case 3: | ||
_b.sent(); | ||
page.on('request', function (req) { | ||
if (req.resourceType() === 'stylesheet' || | ||
req.resourceType() === 'font' || | ||
req.resourceType() === 'script' || | ||
req.resourceType() === 'image') { | ||
req.abort(); | ||
} | ||
else { | ||
req.continue(); | ||
} | ||
}); | ||
return [4 /*yield*/, page.setCookie({ | ||
name: 'user_session', | ||
url: GITHUB_URL, | ||
value: this.userSession, | ||
value: this.options.sessionCookie, | ||
})]; | ||
case 4: | ||
case 2: | ||
_b.sent(); | ||
return [4 /*yield*/, page.goto(GITHUB_URL, { waitUntil: 'domcontentloaded' })]; | ||
case 5: | ||
case 3: | ||
_b.sent(); | ||
_i = 0; | ||
return [4 /*yield*/, page.cookies()]; | ||
case 6: | ||
case 4: | ||
_a = _b.sent(); | ||
_b.label = 7; | ||
case 7: | ||
if (!(_i < _a.length)) return [3 /*break*/, 9]; | ||
_b.label = 5; | ||
case 5: | ||
if (!(_i < _a.length)) return [3 /*break*/, 7]; | ||
cookie = _a[_i]; | ||
@@ -94,8 +91,8 @@ if (cookie.name === 'logged_in' && cookie.value === 'yes') { | ||
} | ||
_b.label = 8; | ||
_b.label = 6; | ||
case 6: | ||
_i++; | ||
return [3 /*break*/, 5]; | ||
case 7: return [4 /*yield*/, page.browser().close()]; | ||
case 8: | ||
_i++; | ||
return [3 /*break*/, 7]; | ||
case 9: return [4 /*yield*/, browser.close()]; | ||
case 10: | ||
_b.sent(); | ||
@@ -108,3 +105,3 @@ throw new Error('InvalidSession'); | ||
return SessionLoginProvider; | ||
}()); | ||
}(LoginProvider_1.LoginProvider)); | ||
exports.SessionLoginProvider = SessionLoginProvider; |
{ | ||
"name": "github-profile-status", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "Update the status of your GitHub profile programmatically", | ||
@@ -35,4 +35,5 @@ "main": "dist/index.js", | ||
"singleQuote": true, | ||
"trailingComma": "all" | ||
"trailingComma": "all", | ||
"printWidth": 100 | ||
} | ||
} |
@@ -10,2 +10,23 @@ <div align="center"> | ||
<details> | ||
<summary>📖 Table of Contents</summary> | ||
<p> | ||
- [Motivation](#motivation) | ||
- [Installation](#installation) | ||
- [Usage](#usage) | ||
- [API](#api) | ||
- [Constructor](#constructor) | ||
- [`new GithubProfileStatus(options: ConstructorOptions)`](#new-githubprofilestatusoptions-constructoroptions) | ||
- [Constructor Options](#constructor-options) | ||
- [Methods](#methods) | ||
- [`GithubProfileStatus.get(): Promise<Status>`](#githubprofilestatusget-promisestatus) | ||
- [`GithubProfileStatus.set(status: Status): Promise<boolean>`](#githubprofilestatussetstatus-status-promiseboolean) | ||
- [Status Object](#status-object) | ||
- [Authentication & Security Disclaimer](#authentication--security-disclaimer) | ||
- [Licence](#licence) | ||
</p> | ||
</details> | ||
## Motivation | ||
@@ -24,3 +45,3 @@ | ||
Unfortunately, at the time of writing this, it's not possible to update the profile status via the API. | ||
Unfortunately, at the time of writing this, this feature is only available via the Github web interface, and it is not possible to update the profile status via the API. | ||
@@ -42,3 +63,7 @@ Therefore, I built this tool to set the status of my Github profile programmatically. | ||
const profileStatus = new GithubProfileStatus({ | ||
session: process.env.USER_SESSION, // the user_session cookie | ||
// login using a user_session cookie | ||
userSession: process.env.USER_SESSION, | ||
// or by using username/password | ||
username: process.env.GITHUB_USERNAME, | ||
password: process.env.GITHUB_PASSWORD, | ||
}); | ||
@@ -49,4 +74,4 @@ | ||
busy: true, | ||
emoji: ':+1:', | ||
message: process.argv[2], | ||
emoji: ':wave:', | ||
message: 'Hello, world!', | ||
}); | ||
@@ -59,4 +84,48 @@ | ||
## API | ||
### Constructor | ||
#### `new GithubProfileStatus(options: ConstructorOptions)` | ||
Creates a new github profile status object using the [provided options](#constructor-options). | ||
#### Constructor Options | ||
- `userSession: string`: The `user_session` cookie of an active login session of the GitHub user account. This can be obtained using the [browser's developer tools](https://developers.google.com/web/tools/chrome-devtools/storage/cookies). | ||
- `username: string`: The username of the GitHub user account. | ||
- `password: string`: The password of the GitHub user account. | ||
Please note that if the `userSession` option is provided, it will be used as the default authentication, ignoring both `username` and `password`. | ||
### Methods | ||
The GitHub profile status instance has the following methods: | ||
#### `GithubProfileStatus.get(): Promise<Status>` | ||
Retrieves the user profile status. Returns a Promise that resolves with the [status object](#status-object). | ||
#### `GithubProfileStatus.set(status: Status): Promise<boolean>` | ||
Updates the user profile status using the provided [status parameters](#status-object). All parameters are optional. If you omit certain parameters, they will remain as they are. | ||
### Status Object | ||
The status object has the following keys: | ||
- `busy: boolean`: A boolean indicating whether the profile status should be displayed as "Busy." | ||
- `message: string`: The status message. | ||
- `emoji: string`: The emoji alias that will be displayed on the status. The emoji alias should be provided in this format `:emoji_name:`. The list of all possible emojis is [available here](https://github.com/wsmd/github-profile-status/blob/master/lib/Emoji.d.ts). | ||
## Authentication & Security Disclaimer | ||
I built this tool for my own personal use. Since the functionality is not provided by the Github API, this tool **does not use any of GitHub's official authentication methods**. | ||
This tool requires either the `user_session` cookie from an active login session of the user account or the user basic login information: username and password. This tool will use this information to connect to the user account via `https://github.com` and perform a status update/check. **I highly encourage providing this information using environment variables**. | ||
While this tool **does not persist or share** any information provided, it is very important that you are aware of the limitation. Please use at your own risk. | ||
## Licence | ||
MIT |
33108
11
523
127