]> git.ardis.lu - ardislu.dev/commitdiff
Add Atom feed
authorArdis Lu <ardisglu@gmail.com>
Wed, 20 Jul 2022 06:23:47 +0000 (23:23 -0700)
committerArdis Lu <ardisglu@gmail.com>
Wed, 20 Jul 2022 06:23:47 +0000 (23:23 -0700)
functions/api.js
functions/atom.xml.js [new file with mode: 0644]
functions/auth.js [new file with mode: 0644]

index dcca070bc8179251dfbb136fe711fc591b089415..7be2d6e631b4c8b609e36864cf35858942a32327 100644 (file)
@@ -1,63 +1,4 @@
-function base64UrlEncode(s) {
-  return btoa(s)
-    .replaceAll('=', '')
-    .replaceAll('+', '-')
-    .replaceAll('/', '_');
-}
-
-async function sign(message, privateKey) {
-  const cleanedKey = privateKey
-    .replace('-----BEGIN PRIVATE KEY-----', '')
-    .replace('-----END PRIVATE KEY-----', '')
-    .replaceAll(/\r\n|\n|\r/g, '');
-  const keyBuffer = Uint8Array.from(atob(cleanedKey), c => c.charCodeAt(0));
-
-  const signingKey = await crypto.subtle.importKey(
-    'pkcs8',
-    keyBuffer,
-    {
-      name: 'RSASSA-PKCS1-V1_5',
-      hash: 'SHA-256'
-    },
-    false,
-    ['sign']
-  );
-
-  const signatureBuffer = await crypto.subtle.sign('RSASSA-PKCS1-V1_5', signingKey, new TextEncoder().encode(message));
-  return base64UrlEncode(String.fromCharCode(...new Uint8Array(signatureBuffer)));
-}
-
-async function getGoogleAuthToken(clientEmail, privateKey, scopes) {
-  const header = base64UrlEncode(JSON.stringify({
-    alg: 'RS256',
-    typ: 'JWT'
-  }));
-
-  const now = Math.round(Date.now() / 1000);
-  const expires = now + 3600;
-  const payload = base64UrlEncode(JSON.stringify({
-    iss: clientEmail,
-    aud: 'https://oauth2.googleapis.com/token',
-    exp: expires,
-    iat: now,
-    scope: scopes
-  }));
-
-  const unsignedJwt = `${header}.${payload}`;
-  const signature = await sign(unsignedJwt, privateKey);
-  const jwt = `${unsignedJwt}.${signature}`;
-
-  const response = await fetch('https://oauth2.googleapis.com/token', {
-    method: 'POST',
-    body: JSON.stringify({
-      assertion: jwt,
-      grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer'
-    })
-  });
-  const oauth = await response.json();
-
-  return oauth.access_token;
-}
+import { getGoogleAuthToken } from './auth.js';
 
 export async function onRequestGet({ request, env }) {
   const url = new URL(request.url);
diff --git a/functions/atom.xml.js b/functions/atom.xml.js
new file mode 100644 (file)
index 0000000..bd6cc58
--- /dev/null
@@ -0,0 +1,41 @@
+import { getGoogleAuthToken } from './auth.js';
+
+export async function onRequestGet({ env }) {
+  const entries = [];
+  const updatedDates = [];
+  const token = await getGoogleAuthToken(env.EMAIL, env.PRIVATE_KEY, env.SCOPES);
+  const sheetUrl = 'https://sheets.googleapis.com/v4/spreadsheets/1pfGF8yBu3D0GPTezygLuzu3Cif8SkjhtG98nL-czlhc/values/B3:I';
+  await fetch(sheetUrl, { headers: { Authorization: `Bearer ${token}` } })
+    .then(r => r.json())
+    .then(googleSheet => {
+      for (const article of googleSheet.values) {
+        entries.push(`<entry>
+          <id>urn:google.com:${article[2]}</id>
+          <title>${article[0]}</title>
+          <summary>${article[1]}</summary>
+          <link href="https://ardislu.dev${article[4]}"/>
+          <published>${new Date(article[5]).toISOString()}</published>
+          <updated>${new Date(article[6]).toISOString()}</updated>
+        </entry>`);
+        updatedDates.push(new Date(article[6]));
+      }
+    });
+
+  const feed = `<?xml version="1.0" encoding="utf-8"?>
+  <feed xmlns="http://www.w3.org/2005/Atom">
+    
+    <id>https://ardislu.dev/</id>
+    <title>ardislu.dev</title>
+    <subtitle>Notes on web development, crypto, self-hosting, and tech in general.</subtitle>
+    <author>
+      <name>Ardis Lu</name>
+    </author>
+    <link href="https://ardislu.dev/"/>
+    <updated>${new Date(Math.max(...updatedDates)).toISOString()}</updated>
+
+    ${entries.join('')}
+
+  </feed>`
+
+  return new Response(feed, { headers: { 'Content-Type': 'application/atom+xml' } });
+}
\ No newline at end of file
diff --git a/functions/auth.js b/functions/auth.js
new file mode 100644 (file)
index 0000000..a6c8a3d
--- /dev/null
@@ -0,0 +1,60 @@
+function base64UrlEncode(s) {
+  return btoa(s)
+    .replaceAll('=', '')
+    .replaceAll('+', '-')
+    .replaceAll('/', '_');
+}
+
+async function sign(message, privateKey) {
+  const cleanedKey = privateKey
+    .replace('-----BEGIN PRIVATE KEY-----', '')
+    .replace('-----END PRIVATE KEY-----', '')
+    .replaceAll(/\r\n|\n|\r/g, '');
+  const keyBuffer = Uint8Array.from(atob(cleanedKey), c => c.charCodeAt(0));
+
+  const signingKey = await crypto.subtle.importKey(
+    'pkcs8',
+    keyBuffer,
+    {
+      name: 'RSASSA-PKCS1-V1_5',
+      hash: 'SHA-256'
+    },
+    false,
+    ['sign']
+  );
+
+  const signatureBuffer = await crypto.subtle.sign('RSASSA-PKCS1-V1_5', signingKey, new TextEncoder().encode(message));
+  return base64UrlEncode(String.fromCharCode(...new Uint8Array(signatureBuffer)));
+}
+
+export async function getGoogleAuthToken(clientEmail, privateKey, scopes) {
+  const header = base64UrlEncode(JSON.stringify({
+    alg: 'RS256',
+    typ: 'JWT'
+  }));
+
+  const now = Math.round(Date.now() / 1000);
+  const expires = now + 3600;
+  const payload = base64UrlEncode(JSON.stringify({
+    iss: clientEmail,
+    aud: 'https://oauth2.googleapis.com/token',
+    exp: expires,
+    iat: now,
+    scope: scopes
+  }));
+
+  const unsignedJwt = `${header}.${payload}`;
+  const signature = await sign(unsignedJwt, privateKey);
+  const jwt = `${unsignedJwt}.${signature}`;
+
+  const response = await fetch('https://oauth2.googleapis.com/token', {
+    method: 'POST',
+    body: JSON.stringify({
+      assertion: jwt,
+      grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer'
+    })
+  });
+  const oauth = await response.json();
+
+  return oauth.access_token;
+}
\ No newline at end of file
This page took 0.054453 seconds and 4 git commands to generate.