Canvas: Github repository picker

Change-Id: Icb8f2ffbef2894b2fdea4e4c13c74c0f4970506b
diff --git a/apps/canvas/back/github.ts b/apps/canvas/back/github.ts
new file mode 100644
index 0000000..f234788
--- /dev/null
+++ b/apps/canvas/back/github.ts
@@ -0,0 +1,51 @@
+import axios from 'axios';
+import { z } from 'zod';
+
+export const GithubRepositorySchema = z.object({
+    id: z.number(),
+    name: z.string(),
+    full_name: z.string(),
+    html_url: z.string(),
+    ssh_url: z.string(),
+});
+
+export type GithubRepository = z.infer<typeof GithubRepositorySchema>;
+
+export class GithubClient {
+    private token: string;
+
+    constructor(token: string) {
+        this.token = token;
+    }
+
+    private getHeaders() {
+        return {
+            "Authorization": `Bearer ${this.token}`,
+            "Accept": "application/vnd.github.v3+json",
+        };
+    }
+
+    async getRepositories(): Promise<GithubRepository[]> {
+        const response = await axios.get("https://api.github.com/user/repos", {
+            headers: this.getHeaders(),
+        });
+        return z.array(GithubRepositorySchema).parse(response.data);
+    }
+
+    async addDeployKey(repoPath: string, key: string) {
+        const sshUrl = repoPath;
+        const repoOwnerAndName = sshUrl.replace('git@github.com:', '').replace('.git', '');
+
+        await axios.post(
+            `https://api.github.com/repos/${repoOwnerAndName}/keys`,
+            {
+                title: "dodo",
+                key: key,
+                read_only: true
+            },
+            {
+                headers: this.getHeaders(),
+            }
+        );
+    }
+} 
\ No newline at end of file