Diskuto: Posts

Diskuto

Why Are The URLs So Long?

You might have noticed that URLs for posts in Diskuto are a bit longer than in other systems. For example, the full URL to the previous post about Diskuto is:

https://blog.nfnitloop.com/u/A719rvsCkuN2SC5W2vz5hypDE2SpevNTUsEXrVFe9XQ7/i/4sVxU7pVvUenEdG41BYJDZJfDBZBjBkLSF7dcGzpGMgtVLbZjTh6w5LzC4Rwjkk5SNyn57o3cfsvEbsZJkFELaW3/

URLs for individual posts are in the format:

{baseUrl}/u/{userID}/i/{signature}/

The userID is, of course, the ID of the user that authored the given post. A userID is randomly generated, so reasonably guaranteed to be globally unique. It also happens to be a cryptographic public key.

The signature is a cryptographic signature which, along with the userID can be used to verify the content in question.

Validating Content

Here's an example Deno script that validates the above post:

#!/usr/bin/env -S deno run --check -EN

const baseUrl = `https://blog.nfnitloop.com`
const userID = `A719rvsCkuN2SC5W2vz5hypDE2SpevNTUsEXrVFe9XQ7`
const signature = `4sVxU7pVvUenEdG41BYJDZJfDBZBjBkLSF7dcGzpGMgtVLbZjTh6w5LzC4Rwjkk5SNyn57o3cfsvEbsZJkFELaW3`

// Given these three things, we can validate that the content on the page
// was in fact created by that user, and has not been modified.

import {Client, Signature, UserID} from "jsr:@diskuto/client@0.10.0"
const client = new Client({baseUrl})

const bytes = await client.getItemBytes(userID, signature)
if (bytes == null) {
    throw new Error(`No such item on this server.`)
}

// Some helper types for working with cryptography:
const uid = UserID.fromString(userID)
const sig = Signature.fromString(signature)

const valid = await sig.isValid(uid, bytes)
if (!valid) {
    throw new Error(`Invalid signature!`)
}

// OK, we have a valid signature for ... some bytes. But is that what's on the page?
// We'll need to inspect the contents of those bytes to verify that the server isn't 
// misrepresenting them:
import { fromBinary, ItemSchema } from "jsr:@diskuto/client/types";
const item = fromBinary(ItemSchema, bytes)
console.log(item)

The output of that script shows us the Markdown body that was used to render the given post:

{
  "$typeName": "Item",
  timestampMsUtc: 1738609806177n,
  utcOffsetMinutes: -480,
  itemType: {
    case: "post",
    value: {
      "$typeName": "Post",
      title: "Diskuto API Release v1.0.0",
      body: "<https://github.com/diskuto/diskuto-api/releases/tag/v1.0.0>\n" +
        "\n" +
        " * Rename to [diskuto-api].\n" +
        "\n" +
        " * Moved to a new GitHub organization: [Diskuto]\n" +
        " \n" +
        " * UI has been rewritten and moved into its own repository as [diskuto-web].  \n" +
        "   Expect most noteworthy changes to happen in this repository moving forward, since\n" +
        "   the API changes much less often.\n" +
        " \n" +
        " * New [full-stack] example for local testing.\n" +
        " \n" +
        " * New OpenAPI schema for the REST API. See: [docs/rest_api/]\n" +
        "\n" +
        "Breaking API Changes\n" +
        "--------------------\n" +
        "\n" +
        " * The REST API has been relocated to `/diskuto/`.  \n" +
        "   This makes it much easier to serve both [diskuto-api] and [diskuto-web] from one web host.\n" +
        "   See: [nginx/default.conf] for an example.\n" +
        "\n" +
        "   Note: The old URLs are still available for backward compatibility but will soon be removed.\n" +
        "\n" +
        " * REST API endpoints have had `/proto3` suffixes removed.  \n" +
        "   These used to be there to distinguish between the HTTP and REST API URLs.\n" +
        "\n" +
        " * Some REST API paths have been renamed to be more user-friendly.  \n" +
        "   Ex: `/u/` -> `/users/`, `/i/` -> `/items/`.\n" +
        "\n" +
        " * See [docs/rest_api/] for details.\n" +
        "\n" +
        "\n" +
        "[diskuto-api]: https://github.com/diskuto/diskuto-api\n" +
        "[diskuto-web]: https://github.com/diskuto/diskuto-web\n" +
        "[Diskuto]: https://github.com/diskuto\n" +
        "[full-stack]: https://github.com/diskuto/diskuto-api/tree/main/examples/full-stack\n" +
        "[docs/rest_api/]: https://github.com/diskuto/diskuto-api/tree/main/docs/rest_api\n" +
        "[nginx/default.conf]: https://github.com/diskuto/diskuto-api/tree/main/examples/full-stack/nginx/default.conf"
    }
  }
}

Redundancy

Because Diskuto is a peer-to-peer, distributed system, the same content can be hosted on multiple servers. If https://blog.nfnitloop.com ever goes down, or starts blocking users or posts, you can replace the baseUrl with some other server to check whether the content is available there.

And if that server gives you a response, you have the tools to validate that it is in fact the content you were looking for.

Indirection

We could shorten the URLs with some indirection.

We could delegate to some external service to resolve usernames into userIDs. (Ex: a well-known URI, a DNS TXT entry, etc.).

We could allow users to specify slugs for posts.

Those changes might enable us to have URLs like:
https://blog.nfnitloop.com/@diskuto@nfnitloop.com/diskuto-api-release-v1.0.0/

But, using that URL doesn't give us the strong guarantees that the longer URLs do. Imagine that a year or more has passed since that URL was posted to some online forum.

  • What if the name-to-id resolution service is down? Or now resolves to some other userID/key?
  • What if the server decides to serve some different content under that slug?

We have no way to verify that the linked content is what was there when the link was originally shared.

Making the userID/signature pair part of the URL gives us more tools for finding and verifying content within the distributed system. It lets Diskuto act like a distributed content-addressable store.

Diskuto

Diskuto API Release v1.0.0

https://github.com/diskuto/diskuto-api/releases/tag/v1.0.0

  • Rename to diskuto-api.

  • Moved to a new GitHub organization: Diskuto

  • UI has been rewritten and moved into its own repository as diskuto-web.
    Expect most noteworthy changes to happen in this repository moving forward, since the API changes much less often.

  • New full-stack example for local testing.

  • New OpenAPI schema for the REST API. See: docs/rest_api/

Breaking API Changes

  • The REST API has been relocated to /diskuto/.
    This makes it much easier to serve both diskuto-api and diskuto-web from one web host. See: nginx/default.conf for an example.

    Note: The old URLs are still available for backward compatibility but will soon be removed.

  • REST API endpoints have had /proto3 suffixes removed.
    These used to be there to distinguish between the HTTP and REST API URLs.

  • Some REST API paths have been renamed to be more user-friendly.
    Ex: /u/ -> /users/, /i/ -> /items/.

  • See docs/rest_api/ for details.

Diskuto

"FeoBlog" is now "Diskuto"

Years ago, I began development on this project as a "small" experiment in designing the kind of social network I wanted to see in the world. I knew, given my visual design skills, that it would be a bit feo to start. I also had (still have) nostalgia for the early "blogging" days of social networking. So "FeoBlog" seemed like a cute name.

But, after using it for myself for years now, I've decided it's time for a new name.

"Diskuto" is an Esperanto word meaning "[a] discussion". I chose it because I hope that the design decisions I've made can help foster better online conversations.

Diskuto isn't just a "blog", it's a protocol and system of software that can be used for several purposes:

  • Simple blogs
  • Following friends, and commenting on their posts
  • Photo/file sharing
  • A "feed reader" that collects news/posts from multiple sources into one chronological view
  • A backup of your social network, including content you follow
  • An offline news reader

And Diskuto doesn't have to be "feo". A big part of recent work has been completely separating the UI from the API server, so that it's easier to develop. It's much simpler to fork the UI and write your own implementation without having to touch any Rust code. I'd love to see other people's takes on how to browse the data in the social network!

The various pieces of the Diskuto system have been collected together into a new GitHub organization, Diskuto. Have a look, and join the Discord server (link here) if you have questions or feedback!

Diskuto

Diskuto updated their profile.

Diskuto

FeoBlog v0.6.0 Released

https://github.com/NfNitLoop/feoblog/releases/tag/v0.6.0

New Features

  • Support for the Open Graph Protocol.
    Now when you share links to other web sites, (or Discord) they'll be able to generate previews if they support OGP.

    Discord Example

  • Quick access to share links.
    Click the arrow at the top-right corner of a post to access share links.

    Share Demo.gif

  • db prune to remove data that's no longer being used.

    image.2.png

  • db usage to see who's hogging all your disk space.
    (See also: The tablestream crate I created to help with this output.)

    image.3.png

Improvements

  • #63 Faster Sync when syncing items between servers.
  • #43 Better browser caching for static files.
  • Logged-in profiles now have a color picker.
    You can set custom background colors for each identity you log in as to help keep them separate.

Bug Fixes

  • Fixed bug (re)rendering widgets when changing pages.
Diskuto

FeoBlog updated their profile.

Diskuto

Official Discord Server

There's now an official Discord server for FeoBlog. If you have questions, feedback, or just want to chat, drop on by!

https://discord.gg/MQKP4MbdF4

Note: Discord invite links can expire, so check this user's profile for the latest link if the above one doesn't work.

Diskuto

FeoBlog v0.5.0 Released

Released: July 18, 2021
https://github.com/NfNitLoop/feoblog/releases/tag/v0.5.0

New Features

  • You can now filter and search your "My Feed" page.
    Is someone posting a bit too much today? You can temporarily hide them from your feed to see what everyone else has to say. Looking for a post you saw last week? Now you can search for a keyword and view only posts/comments that mention that.

    v0.5.0 filter demo

Improvements

  • Posts are no longer clickable.
    Previously, the entire block containing a post was clickable, and would take you to the page for that post. But that resulted in a lot of accidental clicks. Also, since the cursor changed to a pointer for the whole block, it was difficult to see if images were clickable. Now that behavior is gone. You can click on the timestamp of a post to go to a page for just that post.

  • #52 Automatically redirect to the "My Feed" page when logged in.
    If you're logged in, you're probably repeatedly coming to FeoBlog to check your feed. So that's now the default view.

Bug Fixes

  • #51 Draft timestamps could accidentally backdate posts.
  • Fix for nav links that wouldn't highlight when they were clicked.
Diskutocommented

🤦‍♂️ at the double title. The markdown checking can make sure you remember to include your [link] refs, but it can't fix your copy-pasta.

Diskuto

FeoBlog v0.4.0 Released

Version 0.4.0

Released: June 25, 2021 https://github.com/NfNitLoop/feoblog/releases/tag/v0.4.0

  • The web client is now the default view.
    FeoBlog has two ways to access content. One is plain HTML (A.K.A.: Web 1.0), which works well for old browsers and search engines. The other is a web client (Web 2.0), which has a nicer interface. Now, if you visit a page in a browser that supports JavaScript, you'll get automatically redirected to the newer, nicer web client.

  • Post drafts are now saved.
    If you navigate away from the "New Post" page and come back later, your post will still be there. Whew!

  • Added some helpful warnings when writing markdown posts
    Now if you forget to link that [reference], you'll get a warning reminding you to add a link.

  • Better support for password managers
    You should save your private key ("password") in a password manager. But some password managers were filling in the wrong fields. Hopefully that's fixed. (If not, please open an issue!)

  • An updated README to explain the core principles behind FeoBlog's design

  • Support for attachments on iOS (and probably Android)
    Oops. You can't easily drag-and-drop on a phone, so I added a button to attach files. Now you can take photos and easily upload them from your phone!

  • Improved automatic link generation when adding attachments
    When you add an attachment to a post, FeoBlog will generate a [link] and a [link]: files/reference.example for you. Now it'll do a better job of placing those within an existing document.

Diskutocommented

D'oh! I meant to link that GitHub Actions.

Diskuto

FeoBlog v0.3.0 Released

This release brings file attachments to your posts, so bring on the cat pictures!

It also adds automatic builds and releases via [GitHub Actions], which is a nice thing for me. 😊

paste_1614299603061.png

Version 0.3.0

Released: Feb. 25, 2021
https://github.com/NfNitLoop/feoblog/releases/tag/v0.3.0

New Features

  • Attachments!
    You can now attach files to posts by dragging them onto the post editor. A link to the file will be automatically generated for you. If the file is an image, it'll be inlined in your post by default. Syncing between servers will also sync file attachments.
  • Release automation.
    This is more for me than for y'all, but the result of this is that releases should be regularly available via the releases page.

Note: There's a known issue (Bug #16) that is preventing Windows builds from working at the moment. I'll enable Windows builds when that's fixed.

Improvements

  • Switched to comrak for server-side (plain HTML) rendering of Markdown.
    Users shouldn't notice any changes, but this library operates in a "safe by default" mode which is nice.
  • Improved browser caching.
    Protobuf "Items" (and file attachments) are now served with HTTP headers to allow browsers to cache them indefinitely, since they should never change.
  • SQLite's "Write Ahead Logging" ("WAL") mode is now enabled when available, which greatly increases write throughput when syncing. This also means that reads and writes do not block each other.
  • Disable in-browser signature verification during sync.
    This further improves sync speed, since in-browser crypto is particularly slow. The server will still validate that the objects it receives are cryptographically signed. (And the in-browser client still always verifies content signatures before displaying them.)

Bug Fixes

  • Fixed some minor rendering issues when viewing a server w/ no posts.
Diskuto

Version 0.2.0!

Version 0.2.0 is out now.

New Features

  • Comments!
  • Lots of style updates. Items (post/comments) now have a single-line header of metadata.
  • Identicons!
  • Server-side support for replies.
  • New feoblog db upgrade command to keep your database up-to-date with the latest versions of FeoBlog.
  • Relative timestamps. (But you can mouse-over a date to see absolute times.)

And more. See all the details on GitHub

Diskuto

Example Client

Curious how easy it is to write a client for FeoBlog?

Check out fb-rss.py, a utility to sync an RSS feed into FeoBlog.

Diskuto

FeoBlog updated their profile.

Diskuto

Demo Video

A video demo of the features available in v0.1.0 is now available on YouTube.

If you're interested in learning more, but haven't had time to set up your own server, hopefully this will help!

Diskuto

Public Release

The first publicly released version of FeoBlog, version 0.1.0 is now available on GitHub! 🎉

https://github.com/NfNitLoop/feoblog

Diskuto

Hello, World!

This is the first post on my public FeoBlog server. 🎉

Tomorrow, I'll work to get the source code cleaned up and published to GitHub so people can run their own servers. For today, ping me personally if you want to be an early tester. :)

Diskuto

FeoBlog updated their profile.