Skip to content

Commit

Permalink
Decorate
Browse files Browse the repository at this point in the history
  • Loading branch information
Quantumlyy committed Jul 20, 2020
1 parent cb57705 commit e595b2a
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 23 deletions.
3 changes: 2 additions & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
/src/commands/Google/ @favna
/src/commands/Misc/reddituser.ts @favna
/src/commands/Pokemon/ @favna
/src/commands/Twitch/ @favna
/src/commands/tools/Websearch/eshop.ts @favna
/src/commands/tools/Websearch/igdb.ts @favna
/src/commands/tools/Websearch/itunes.ts @favna
Expand All @@ -26,7 +27,7 @@

# QuantumlyTangled
/src/commands/GameIntegration/ffxiv.ts @quantumlytangled
/src/commands/Twitch/ @quantumlytangled
/src/commands/Notifi/ @quantumlytangled
/src/events/analytics/ @quantumlytangled
/src/events/twitch/ @quantumlytangled
/src/lib/orm/migrations/1594757329224-V13_MigrateAnalytics.ts @quantumlytangled
Expand Down
18 changes: 5 additions & 13 deletions src/lib/util/Notifications/Twitch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { PubSubHubbubAction } from '@lib/types/Enums';
import { TOKENS, TWITCH_CALLBACK } from '@root/config';
import { Mime, Time } from '@utils/constants';
import { enumerable, fetch, FetchMethods, FetchResultTypes } from '@utils/util';
import { createHmac } from 'crypto';
import { RateLimitManager } from 'klasa';

export interface OauthResponse {
Expand Down Expand Up @@ -31,9 +30,6 @@ export class Twitch {
@enumerable(false)
private readonly $clientSecret = TOKENS.TWITCH_SECRET;

@enumerable(false)
private readonly $webhookSecret = TOKENS.TWITCH_WEBHOOK_SECRET;

@enumerable(false)
private readonly kTwitchRequestHeaders = {
'Content-Type': Mime.Types.ApplicationJson,
Expand Down Expand Up @@ -69,14 +65,6 @@ export class Twitch {
return this._performApiGETRequest<TwitchHelixResponse<TwitchHelixUserFollowsResult> & { total: number }>(`users/follows?from_id=${userID}&to_id=${channelID}`);
}

public checkSignature(algorithm: string, signature: string, data: any) {
const hash = createHmac(algorithm, this.$webhookSecret)
.update(JSON.stringify(data))
.digest('hex');

return hash === signature;
}

public fetchBearer() {
const { TOKEN, EXPIRE } = this.BEARER;
if (!EXPIRE || !TOKEN) return this._generateBearerToken();
Expand All @@ -91,7 +79,7 @@ export class Twitch {
'hub.mode': action,
'hub.topic': `https://api.twitch.tv/helix/streams?user_id=${streamerID}`,
'hub.lease_seconds': (9 * Time.Day) / Time.Second,
'hub.secret': this.$webhookSecret
'hub.secret': Twitch.$webhookSecret
}),
headers: {
...this.kTwitchRequestHeaders,
Expand Down Expand Up @@ -121,6 +109,10 @@ export class Twitch {
return respone.access_token;
}


@enumerable(false)
public static $webhookSecret = TOKENS.TWITCH_WEBHOOK_SECRET;

}

export const TWITCH_REPLACEABLES_REGEX = /%ID%|%TITLE%|%VIEWER_COUNT%|%GAME_NAME%|%GAME_ID%|%LANGUAGE%|%USER_ID%|%USER_NAME%/g;
Expand Down
41 changes: 41 additions & 0 deletions src/lib/util/Notifications/hubSignature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { isObject } from '@klasa/utils';
import { ApiRequest } from '@lib/structures/api/ApiRequest';
import { ApiResponse } from '@lib/structures/api/ApiResponse';
import { createFunctionInhibitor } from '@skyra/decorators';
import { createHmac } from 'crypto';

export function hubSignature(secret: string) {
return createFunctionInhibitor(
(request: ApiRequest, response: ApiResponse) => {
if (!isObject(request.body)) {
response.badRequest('Malformed data received');
return false;
}

const xHubSignature = request.headers['x-hub-signature'];
if (typeof xHubSignature === 'undefined') {
response.badRequest('Missing "x-hub-signature" header');
return false;
}

const [algo, sig] = xHubSignature.toString().split('=', 2);
if (!checkSig(algo, sig, secret, request.body)) {
response.forbidden('Invalid Hub signature');
return false;
}

return true;
},
(_request: ApiRequest, response: ApiResponse) => {
response.badRequest('x-hub-signature');
}
);
}

export function checkSig(algorithm: string, signature: string, secret: string, data: any) {
const hash = createHmac(algorithm, secret)
.update(JSON.stringify(data))
.digest('hex');

return hash === signature;
}
12 changes: 3 additions & 9 deletions src/routes/twitch/twitchStreamChange.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { isObject } from '@klasa/utils';
import { ApiRequest } from '@lib/structures/api/ApiRequest';
import { ApiResponse } from '@lib/structures/api/ApiResponse';
import { Events } from '@lib/types/Enums';
import { ApplyOptions } from '@skyra/decorators';
import { hubSignature } from '@utils/Notifications/hubSignature';
import { PubSubHubbubRoute } from '@utils/Notifications/structures/PubSubHubbubRoute';
import { Twitch } from '@utils/Notifications/Twitch';
import { AnalyticsSchema } from '@utils/Tracking/Analytics/AnalyticsSchema';
import { RouteOptions } from 'klasa-dashboard-hooks';

Expand All @@ -13,15 +14,8 @@ import { RouteOptions } from 'klasa-dashboard-hooks';
export default class extends PubSubHubbubRoute {

// Stream Changed
@hubSignature(Twitch.$webhookSecret)
public post(request: ApiRequest, response: ApiResponse) {
if (!isObject(request.body)) return response.badRequest('Malformed data received');

const xHubSignature = request.headers['x-hub-signature'];
if (typeof xHubSignature === 'undefined') return response.badRequest('Missing "x-hub-signature" header');

const [algo, sig] = xHubSignature.toString().split('=', 2);
if (!this.client.twitch.checkSignature(algo, sig, request.body)) return response.forbidden('Invalid Hub signature');

const id = request.params.id as string;
const { data } = request.body as PostStreamBody;
const lengthStatus = data.length === 0;
Expand Down

0 comments on commit e595b2a

Please sign in to comment.