Adding a bot obviously hurts decentralization. Public groups/channels in principle could be fetched without it, but that’s much more difficult.

Oh. I actually experimented a bit and there’s no need to add a bot! Any bot, even not present in the channel, can make these queries. Then it’s just an extremely simple HTTP API with two methods.

    A lot of information here. I'll need to do some testing on my end. We also really need to make sure there are no obvious side channels through which this could be abused.

    Glancing at the PR, we'll have a few things to improve. I think tg:user=complex_user_1234&chat=complex_chat_1234 as a claim is a good start but it's a big departure from all other identity claims, which are (when possible) valid URLs that people can visit.

    How about we use https://t.me/hoCheiya5tie8aevei5da4xa4aequ4lo?user=complex_user_1234?

    Also, I do think we can use the telegram ID and make sure the Keyoxide client simply shows the associated username? That way, the claim can stay identical but the interface will show the current username.

    There‘s no simple way to get username from ID, as far as I know.

    We can validate both, but that’s about just as brittle as validating just username and also requires providing some One True Way of discovering own ID.

    So what does the API return when you fetch a message? The ID or the username?

    Both. Example outputs:

    {
      "ok": true,
      "result": {
        "id": -1001668437313,
        "title": "thequei8zeepae0xi7to4chui2Hohcha",
        "username": "thequei8zeepae0xi7to4chui2Hohcha",
        "type": "supergroup",
        "description": "0baf2d87cb43746f62372d78de6031aba0bb269a",
        "permissions": {
          "can_send_messages": false,
          "can_send_media_messages": false,
          "can_send_polls": false,
          "can_send_other_messages": false,
          "can_add_web_page_previews": false,
          "can_change_info": false,
          "can_invite_users": false,
          "can_pin_messages": false
        },
        "join_to_send_messages": true,
        "pinned_message": {
          "message_id": 3,
          "from": {
            "id": 1136612192,
            "is_bot": false,
            "first_name": "Max",
            "username": "goldsteinq",
            "language_code": "en"
          },
          "chat": {
            "id": -1001668437313,
            "title": "thequei8zeepae0xi7to4chui2Hohcha",
            "username": "thequei8zeepae0xi7to4chui2Hohcha",
            "type": "supergroup"
          },
          "date": 1660204801,
          "text": "this is a verification message"
        }
      }
    }

    and

    {
      "ok": true,
      "result": [
        {
          "user": {
            "id": 1136612192,
            "is_bot": false,
            "first_name": "Max",
            "username": "goldsteinq",
            "language_code": "en"
          },
          "status": "creator",
          "is_anonymous": false
        }
      ]
    }

    Awesome! So then we use the ID to verify the identity and show the username in the UI! Thx for the logs. I'll try and test your code tonight.

    Goldstein Oh. I actually experimented a bit and there’s no need to add a bot! Any bot, even not present in the channel, can make these queries. Then it’s just an extremely simple HTTP API with two methods.

    This is not my experience in my testing. If I don't add my bot to the channel, I get a "CHAT_ADMIN_RIGHTS" error message. Am I doing something wrong?

    You need to create a public group (you can disable posting, so it would be like a channel), not a public channel.

    Goldstein Public group admins are visible to everyone though, and there’s an option to disable posting in the group, so it becames a de-facto channel

    It's not easy to make a group. I have to add somebody and if I add a single person, it just makes a private chat. How did you make such a group chat?

    1. Click “New group”, enter group name, add any dummy user as a second (we can suggest adding Keyoxide bot, it doesn’t really matter).
    2. In your new group, click on three dots → manage group → group type → public and choose any username.
    3. In manage group → permissions uncheck all the checkboxes, so nobody but you can send a message.
    4. Set the description to fingerprint.
    5. Done! Now my PR would recognize this group as a proof of your identity.

    Step 3 is optional, but probably makes sense, since proof will be posted in public.

    Must have done something wrong on my first attempt. Yup, this works, thanks for the instructions!

    Ok, tested with your code and it works fine! Marvelous work, the method you are proposing seems solid to me. I'll need to think about it a bit more, see if I can find flaws but we'll likely go this route.

    Now let's refine that PR and get it merged!

    Goldstein There’s an another interesting question: what should be verified? Telegram username is user-readable, but also easy to change. Telegram id is immutable, but is kinda useless

    I am still a bit divided on this.

    Username pros:

    • can directly be used to make the personal URL
    • is human readable
    • easy to find from the clients

    Username cons:

    • not immutable (-> people changing their username just need to update the claim)

    ID pros:

    ID cons:

    • not human readable
    • hard to find from the clients

    Looking at the pros and cons, I think the username is the best fit. All opinions welcome on this one (pinging @wiktor)

    ---update

    Do we need anything at all? If DOIP detects a single administrator, that will automatically be the telegram account to verify. If for some reasons there are multiple admins (people helping others with creating their proof group?), the claim MAY add a username= parameter or a id= parameter simply to let DOIP know what account to verify.

    ---update2

    if (admin.status === 'creator') {
        creator = admin.user.username
    }

    Isn't this the argument we don't need anything at all? Surely, there can only be one creator, so that must be the account to verify.

    Yes, we could include only the channel link, but I don’t like that it’s hard to open the user account with only a channel link. Maybe I’d even suggest a reverse strategy:

    https://t.me/goldsteinq?proof=hoCheiya5tie8aevei5da4xa4aequ4lo

    which leads to a user account when clicked (and Keyoxide can easily form a proof link to display in UI).

      I’d also like to note that the channel/group usernames, just like, ehm, user usernames are mutable.

        Goldstein

        I'm so glad you are proposing this strategy, I was thinking of the same thing! It has an upside and a downside.

        Upside: you link straight to where you want to be, the profile
        Downside: it will be near impossible just by clicking the link to find the proof for manual verification

        I want to believe that the downside is mitigated because, well, that's what Keyoxide is for! But as you mentioned, Keyoxide will show a link to the actual proof for manual verification. If you are a hardcore user that skips Keyoxide's UI, well then you probably have the knowledge to figure out that the ?proof= parameter represents the public group with the proof.

        I think I prefer this https://t.me/USERNAME?proof=GROUPNAME strategy.

        Goldstein I’d also like to note that the channel/group usernames, just like, ehm, user usernames are mutable.

        True, hadn't considered that. But let's face it, you really have to try and sabotage yourself to change the name of the proof group. If one wants to, great! Their responsibility to update their claim. The documentation will state what happens in such cases.

        Looking at the https://t.me/USERNAME source code, they actually do use URIs!

        tg://resolve?domain=USERNAME

        Since https://t.me/USERNAME appears to automatically attempt to open that URI, I don't it's worth it to prefer the URI over the URL. If the verifier doesn't have a native Telegram app, the URI will be useless, at least the URL gives them some information.