— sekitar 5 menit membaca

Lume: Gotosocial comment's

Cara menampilkan gotosocial mentions sebagai comments

Di lume tidak perlu memasang plugin untuk bisa memasang mastodon comment’s, cukup dengan web component1 saja.

Dokumentasi Lume tidak menyertakan tentang info cara memasangnya, jadi saya akan coba menulis tentang pengalaman memakai mastodon comment’s ini. Karena memakai web component maka script dibuat dengan Javascript yang bisa diembed di dalam HTML.

Tapi sebelum itu saya buat folder khusus untuk menyimpan Javascript, foldernya dibuat di dalam folder _src sehingga pathnya kira - kira seperti ini

/_src
   /js
      - comments.js
      - comments.css
      - main.js

Kemudian di dalam folder js bikin 1 file dengan nama main.js dan isinya adalah

import Comments from "./comments.js";
customElements.define("mastodon-comments", Comments);

selanjutnya script tersebut dipanggil saat halaman dibuka dengan cara menambahkan dalam tag header di dalam file HTML. Di Lume saya membuat templates header.vto dan di dalamnya saya tambahkan

<script src="/js/main.js" type="module"></script>

Karena file main.js ini mengimport fungsi Comments dari file comments.js yang saya belum punya, maka saya perlu mengunduh file tersebut. Di Lume ada 2 cara,

  1. Mempergunakan fungsi/fitur site.remote() Remote files untuk mengunduh file saat build atau
  2. Mengunduh dan menyimpannya secara manual2

Saya pilih cara yang kedua, jadi saya unduh file comments.js dari repositorinya di https://github.com/oom-components/mastodon-comments lalu disimpan ke dalam folder js yang sudah dibuat sebelumnya.

Kemudian di lokasi yang hendak ditampilkan mastodon comment’s (punya saya di dalam template layout/jurnal.vto) , tambahkan template tags seperti ini

{{ if it.comments?.src }}
<div class="comments-section">
  <header class="comments-header">
    <h2>{{ metadata.comments.title }}</h2>
    <p>{{ metadata.comments.description.replace(":src:", it.comments.src) }}</p>
  </header>
  <mastodon-comments
    src="{{ it.comments.src }}"
    cache="{{ it.comments.cache ?? 60 }}"
    class="comments">
    {{ metadata.comments.empty }}
  </mastodon-comments>
</div>
{{ /if }}

di frontmatter di file artikel, tambahkan variable comments : src: agar bisa menjadi hook untuk template tags di atas.

---
comments:
  src: "https://mastodon.social/@monsterpoes/112671781345375943"
---

variable ini yang akan dibaca dan ditampilkan isi dari replynya. Terakhir tinggal pasang stylesheet bisa dengan bikin sendiri atau pakai yang sudah jadi seperti dari mastodon-comments/src/styles.css at main · oom-components/mastodon-comments.

Selesai gampang dan mudah kalo pakai akun Mastodon tapi untuk Gotosocial oh tunggu dulu, banyak hal yang harus dibenahi.

Gotosocial #

Gotosocial memiliki struktur URL yang berbeda dibandingkan dengan Mastodon2. Strukturnya seperti ini

https://kauaku.us/@poes/statuses/01J1S8G6667MYN5R2XYVN5D2WG

ada path /statuses setelah handler username. Ini membuat mastodon comment’s tidak bisa langsung memparse status ID untuk melakukan fetching data. Tapi di dalam file comments.js sudah disisipkan script yang bisa dipergunakan untuk instance Pleroma yang juga memiliki struktur URL berbeda, sehingga bisa dimanfaatkan dengan sedikit modifikasi sebagai berikut

// Gotosocial with /statuses/ in url
if (pathname.includes("/statuses/")) {
  [, id] = pathname.match(/^\/@poes\/statuses\/([^\/?#]+)/);
} else {
  [, id] = pathname.match(/\/(\d+)$/);
}

dengan ini mastodon comment’s bisa mengparse status ID untuk mengfetch data. Bagus!

Eh tapi,

ternyata tidak cukup sampai disini, Gotosocial tidak mengijinkan fetch tanpa authentification, harus pakai token jadi request dulu token dengan cara seperti tutorial Authentication With API.

Setelah mendapatkan token, maka fungsi fetch harus dirubah untuk mengikutkan token. Saya menghubungi developer mastodon comments untuk Lume ini dan dia mengupdate kodenya agar bisa memakai token.

Dengan ini mastodon comments sudah bisa melakukan fetch dan display data sesuai dengan yang diinginkan. Keren! tapi cara seperti ini cocok untuk pemakaian lokal saja, setelah push dan live cara ini sangat beresiko keamanan karena token akan kelihatan di browser. Ini adalah resiko jika mempergunakan web component karena berjalan disisi client / browser.

Proxy #

Oleh karena itu dibutuhkan semacam proxy sebagai jembatan. Konsepnya kira - kira seperti ini

  1. token disimpan sebagai .env di proxy yang bisa dipakai memanggil API dalam format JSON,
  2. mastodon comment’s melakukan fetching ke proxy. Dalam proses ini tidak mempergunakan token.

Jadi akhirnya saya bikin proxy sederhana di Deno Deploy, scriptnya kira - kira seperti ini

Deno.serve({ port: 8000 }, async (request) => {
  const { pathname, search } = new URL(request.url);
  const url = new URL("." + pathname, "https://kauaku.us");
  url.search = search;

  const headers = new Headers(request.headers);
  headers.set("Access-Control-Allow-Origin", "*");
  headers.set("Authorization", `Bearer ${Deno.env.get("GTS_TOKEN")}`);

  return fetch(url, {
    method: request.method,
    headers,
    body: request.body,
    redirect: "manual",
  });
});

untuk token saya simpan di environment variable yang disediakan oleh Deno dan dipanggil dengan Deno.env.get(‘GTS_TOKEN’).

Kemudian di frontmatter tinggal dirubah srcnya menjadi alamat proxy yang dipakai, dalam hal ini saya pakai URL https://poestodon.deno.dev yang akan mengrelay proxy ke URL asli.

https://poestodon.deno.dev/@poes/statuses/01J1S8G6667MYN5R2XYVN5D2WG

abaikan media yang tidak bisa ditampilkan, itu tak penting yang penting bisa dipakai untuk fetching data dan token aman.

Setelah melakukan itu semua akhirnya saya bisa menampilkan gotosocial threads (jika ada) di Lume.

26 Juli 2024 : Update terkait proxy #

Mempergunakan proxy seperti ini tidak aman karena Token tersedia di semua URL yang dibuka sehingga potensi serangan XSS. Saya menyingkirkan proxy ini dan membuat end point API baru untuk mengakomodir ini4

Di Deno scriptnya kira - kira seperti ini:

import { Hono } from "jsr:@hono/hono";
import { cors } from "jsr:@hono/hono/cors";

const app = new Hono();

app.use(
  "/gts/*",
  cors({
    origin: "https://kusaeni.com",
    allowHeaders: ["X-Custom-Header", "Upgrade-Insecure-Requests"],
    allowMethods: "GET",
    exposeHeaders: ["Content-Length", "X-Kuma-Revision"],
    maxAge: 600,
    credentials: true,
  }),
);

app.get("/gts/:id", async (c: any) => {
  const id = c.req.param("id");
  const f = await fetch(`https://kauaku.us/api/v1/statuses/${id}/context`, {
    method: "GET",
    headers: {
      "Content-Type": "Application/json",
      Authorization: `Bearer ${Deno.env.get("GTS_TOKEN")}`,
    },
  });
  const t = await f.json();
  return c.json(t);
});

Deno.serve(app.fetch);

Kemudian di file comments.js saya rubah fungsi fetch menjadi sebagai berikut:

const data = await Mastodon.fetch(new URL(`https://sepoi.deno.dev/gts/${id}`), this);

Semoga dengan perubahan ini bisa menghilangkan masalah XSS/Inject script.


Artikel terkait #lume

Lume: Memblokir bot crawler AI

Saya membuat middleware untuk memblock akses bot crawler AI di blog ini.


kembali ke atas