辛宝Otto

辛宝Otto 的玄酒清谈

北漂前端程序员儿 / 探索新事物 / Web Worker 主播之一/内向话痨
xiaoyuzhou
email

【Technical perspective of playing with xlog】A smoother user experience 2 Understanding the authentication of xlog in depth.

image.png

This article continues the exploration and builds on the content of the article "[Technical Exploration of xlog] Smoother User Experience 1 Feasibility Study".

In this article, we will attempt to implement the management of xlog articles, allowing us to add, delete, modify, and search our own content based on the official openapi. This article is worth 5 coins as appreciation. Hehe.

Background

To implement the management of xlog articles, we need authorization. How do we prove that you are you and that you can modify someone else's article? In the web2 domain, we usually generate a JWT token using an account password to simulate a user, or obtain an access token through OAuth to authorize specific permissions.

Our technical premise is any runtime environment that supports different runtime environments such as browsers and node.js, so we will not consider authorization methods like the web browser extension Metamask.

Technical Implementation

After some exploration and guidance from the official member diygod, there are currently at least two ways to implement data authorization management: private key and authorization code, with the second method being recommended.

Using Private Key

The first method is to use a private key, which is the wallet's private key. This is a universal solution to prove that I am the owner. The official SDK also supports authorization through private keys.

For example, here is the link: https://crossbell.js.org/#md:connect-with-private-key

Where does the private key come from? Let's take the example of the web browser extension:

image.png

In the account details, there is an option to "Show Private Key". By using the official SDK, we can implement authorization.

Please note: the private key is highly confidential and using it is very risky. This is only for technical demonstration purposes.

For users and developers, the following method is recommended: the authorization token method.

Using siwe Authorization

SIWE stands for "sign in with ethereum".

There are several steps to authorize using siwe:

  • Enable siwe functionality
  • Obtain a token
  • Obtain authorization through an API

Enable siwe Functionality

First, visit your xlog dashboard at https://xlog.app/dashboard/ and select "Settings" in the last column of the left menu.

Select "xSettings" and you will see the following display:

image.png

I am not very familiar with web3, so let me explain the content in the circular frame in plain language, mainly the Sync Operator section:

  • Operation authorization.
  • Synchronized operation. By enabling Sync Operator, you can allow content to be synchronized to Crossbell (xlog) through other means.

Once enabled, we have the ability to synchronize content to xlog through code.

Obtain a Token

Currently, the simplest way to obtain a token is to perform the following steps in the console of the xsetting page:

On the xsetting page, right-click and select "Inspect", or enable developer mode, or press F12. It is recommended to use Chrome. A module will pop up, select the "Console" tab, copy the code below into the console, press Enter, and a long string of text will be returned.

JSON.parse(localStorage.getItem('connect-kit:account')).state.wallet.siwe.token

This code is used to obtain the siwe token information. There may be other ways to obtain it, but currently this is the simplest method.

The content returned by this code is the required token information. Please save it yourself.

Please note that there should be no single quotes on both ends, only the content. (Well, I'll make a foolproof design and make the program compatible.)

Please copy the long content returned by the console. This is the authorization token that will be used in the plugin.

For developers, it can be stored in a .env file in a node.js project or in a secret in GitHub to avoid exposing it in plain text.

API Practice

With the token obtained earlier, we can visit the official documentation provided by https://indexer.crossbell.io/docs#/Siwe. Everything we need is here.

image.png

Scroll to the top of the page, there is a green "Authorize" button. Clicking it will open a popup window where you can enter the token obtained earlier into the siwe field.

image.png

Click "Authorize", and now the header of each request will include Authorization: Bearer ${token}.

For example, we can use GET /v1/siwe/account to find out who we are.

image.png

The rest is simple. Here are a few APIs you can try on your own:

  • PUT /v1/siwe/contract/characters/{characterId}/notes to create a new article for a user
  • POST /v1/siwe/contract/characters/{characterId}/notes/{noteId}/metadata to update a specific noteId article
  • DELETE /v1/siwe/contract/characters/{characterId}/notes/{noteId} to delete a specific article

Here are a few code snippets that have been tested and are effective.

First, creating an article:

const title = 'Article Title'
const content = 'Article Content'
const base = "https://indexer.crossbell.io";
const ottoCharId = ''
const token = ''

const createPost = async () => {
  const url = `/v1/siwe/contract/characters/${ottoCharId}/notes`;

  const finalUrl = base + url;

  axios
    .request({
      method: "put",
      url: finalUrl,
      headers: {
        Authorization: `Bearer ${token}`,
      },
      data: {
        metadata: {
          tags: ["post"],
          type: "note",
          title: title,
          content: content,
          summary: "",
        sources: ["xlog"],
          attributes: [
            {
              value: "play-xlog-01", // Custom slug here
              trait_type: "xlog_slug",
            },
          ],
          attachments: [
            {
              name: "cover", // cover
              address: "",
              mime_type: "",
            },
          ],
        },
        locked: false,
        linkItemType: null,
      },
    })
    .then((res) => {
      console.log(2, res.data);
    })
    .catch((err) => {
      console.log(3, err);
    });
};

Next, updating an article. Note that the mode parameter is straightforward, "replace" is simpler to understand than "merge".

const updatePost = async () => {
  const noteId = 29;
  const mode = "replace"; //'merge'

  const updatePost =
    base +
    `/v1/siwe/contract/characters/${ottoCharId}/notes/${noteId}/metadata`;

  axios
    .request({
      method: "post",
      url: updatePost,
      headers: {
        Authorization: `Bearer ${token}`,
      },
      data: {
        metadata: {
          tags: ["post", "new idea"],
          type: "note",
          title: title,
          content: content,
          sources: ["xlog"],
          // summary: "",
          attributes: [
            {
              value: "play-xlog-01",
              trait_type: "xlog_slug",
            },
          ],
          attachments: [
            {
              name: "cover",
              address: "",
              mime_type: "",
            },
          ],
        },
        mode,
      },
    })
    .then((res) => {
      console.log(JSON.stringify(res.data, null, 2));
    })
    .catch((err) => {
      console.log(3, err);
    });
};

Finally, deleting an article:

const deletePost = async () => {
  const characterId = '';
  const noteId = '';

  const deletePost =
    base + `/v1/siwe/contract/characters/${characterId}/notes/${noteId}`;

  axios
    .request({
      method: "delete",
      url: deletePost,
      headers: {
        Authorization: `Bearer ${token}`,
      },
    })
    .then((res) => {
      console.log(2, res.data);
    })
    .catch((err) => {
      console.log(3, err);
    });
};

Pitfall Experience

The request body for creating an article is different from the response body for getting the list. The main difference is whether the content is wrapped in an additional layer. It was a bit tricky, but the final parameter for creating an article is valid.

The official API is quite tolerant of input parameters, accepting any parameters. This caused a lot of confusion when the list page couldn't be displayed. It took a long time to troubleshoot, so be extremely careful and double-check. Once you are familiar with the official source code, you can add some restrictions.

Outlook

With the API practices mentioned above, we can achieve the following in the future:

  • Write a Node.js script to create and update articles
  • For example, in GitHub actions, every time a markdown file is pushed, a function can be called to synchronize it to xlog
  • For example, in Obsidian, write a plugin to upload to xlog with a right-click
  • Integrate with our own CMS backend for article management

Next, I will modify my Obsidian plugin to upload files to xlog.

image.png

Stay tuned.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.