Skip to content

Commit

Permalink
feat: Trigger github sync on push
Browse files Browse the repository at this point in the history
  • Loading branch information
pawanpaudel93 committed Feb 16, 2024
1 parent afbc2ba commit bc5dfc5
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/lib/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const trackAmplitudeAnalyticsEvent = async (
wallet: any,
data?: Record<any, any>
) => {
return;
try {
let eventOptions: { user_id?: string; device_id?: string } = {
user_id: undefined,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const PL_TMP_PATH = '.protocol.land';
export const GIT_CONFIG_KEYFILE = 'protocol.land.keyfile';
export const GIT_CONFIG_THRESHOLD_COST = 'protocol.land.thresholdCost';
export const getWarpContractTxId = () =>
'w5ZU15Y2cLzZlu3jewauIlnzbKw-OAxbN9G5TbuuiDQ';
'B8gmo1897cyCjShP7QRe1XndatqLMieeymxehBK_oL8';
// get gitdir (usually '.git')
export const gitdir = process.env.GIT_DIR as string;

Expand Down
105 changes: 105 additions & 0 deletions src/lib/githubSync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import Arweave from 'arweave';
import crypto from 'crypto';
import type { PrivateState, Repo } from '../types';
import { getActivePublicKey, getAddress } from './arweaveHelper';
import { log } from './common';
import {
decryptAesKeyWithPrivateKey,
decryptFileWithAesGcm,
} from './privateRepo';

export async function deriveAddress(publicKey: string) {
const arweave = Arweave.init({
host: 'ar-io.net',
port: 443,
protocol: 'https',
});

const pubKeyBuf = arweave.utils.b64UrlToBuffer(publicKey);
const sha512DigestBuf = await crypto.subtle.digest('SHA-512', pubKeyBuf);

return arweave.utils.bufferTob64Url(new Uint8Array(sha512DigestBuf));
}

async function decryptPAT(
encryptedPATString: string,
privateStateTxId: string
): Promise<string> {
const arweave = new Arweave({
host: 'ar-io.net',
port: 443,
protocol: 'https',
});

const encryptedPAT = arweave.utils.b64UrlToBuffer(encryptedPATString);
const response = await fetch(`https://arweave.net/${privateStateTxId}`);
const privateState = (await response.json()) as PrivateState;
const ivArrBuff = arweave.utils.b64UrlToBuffer(privateState.iv);

//public key -> hash -> get the aes key from object
const pubKey = await getActivePublicKey();
const address = await deriveAddress(pubKey);

const encAesKeyStr = privateState.encKeys[address];
const encAesKeyBuf = arweave.utils.b64UrlToBuffer(encAesKeyStr!);

const aesKey = (await decryptAesKeyWithPrivateKey(
encAesKeyBuf
)) as unknown as ArrayBuffer;
const accessToken = await decryptFileWithAesGcm(
encryptedPAT,
aesKey,
ivArrBuff
);

return new TextDecoder().decode(accessToken);
}

export async function triggerGithubSync(repo: Repo) {
try {
if (!repo) return;

const githubSync = repo.githubSync;
if (!githubSync || !githubSync?.enabled) return;

const connectedAddress = await getAddress();
const isAllowed =
githubSync.allowed.findIndex(
(address) => address === connectedAddress
) > -1;

if (
!isAllowed ||
!githubSync.repository ||
!githubSync.workflowId ||
!githubSync.branch
)
return;

const accessToken = await decryptPAT(
githubSync.accessToken,
githubSync.privateStateTxId
);

if (!accessToken) return;

const response = await fetch(
`https://api.github.com/repos/${githubSync?.repository}/actions/workflows/${githubSync?.workflowId}/dispatches`,
{
method: 'POST',
headers: {
Accept: 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify({ ref: githubSync?.branch, inputs: {} }),
}
);

if (response.status === 204) {
log('Successfully synced to GitHub Successfully');
}
} catch (err) {
//
}
}
4 changes: 2 additions & 2 deletions src/lib/privateRepo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ async function encryptDataWithExistingKey(
return encrypted;
}

async function decryptAesKeyWithPrivateKey(encryptedAesKey: Uint8Array) {
export async function decryptAesKeyWithPrivateKey(encryptedAesKey: Uint8Array) {
const privateKey = getWallet();
const key = await crypto.subtle.importKey(
'jwk',
Expand All @@ -65,7 +65,7 @@ async function decryptAesKeyWithPrivateKey(encryptedAesKey: Uint8Array) {
return new Uint8Array(decryptedAesKey);
}

async function decryptFileWithAesGcm(
export async function decryptFileWithAesGcm(
encryptedFile: ArrayBuffer,
decryptedAesKey: ArrayBuffer,
iv: Uint8Array
Expand Down
3 changes: 3 additions & 0 deletions src/lib/remoteHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
trackRepositoryCloneEvent,
trackRepositoryUpdateEvent,
} from './analytics';
import { triggerGithubSync } from './githubSync';

// string to check if objects were pushed
const OBJECTS_PUSHED = 'unpack ok';
Expand Down Expand Up @@ -223,6 +224,8 @@ const spawnPipedGitCommand = async (
}

if (success) {
await triggerGithubSync(repo);

log(`Successfully pushed repo '${repo.id}' to Protocol Land`, {
color: 'green',
});
Expand Down
12 changes: 12 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,20 @@ export type Repo = {
parent: string | null;
private: boolean;
privateStateTxId?: string;
githubSync: GithubSync | null;
};

export interface GithubSync {
enabled: boolean;
repository: string;
branch: string;
workflowId: string;
accessToken: string;
privateStateTxId: string;
allowed: Array<string>;
pending: Array<string>;
}

export type PrivateState = {
iv: string;
encKeys: Record<string, string>;
Expand Down

0 comments on commit bc5dfc5

Please sign in to comment.