Skip to content

Instantly share code, notes, and snippets.

@marph91
Last active June 12, 2023 17:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marph91/fde8307819b3001b6155e55220aac062 to your computer and use it in GitHub Desktop.
Save marph91/fde8307819b3001b6155e55220aac062 to your computer and use it in GitHub Desktop.
Script for generating an user API key for discourse.
"""
Script for generating an user API key for discourse.
Requirements:
pip install pycryptodomex
Usage:
python generate_api_key.py --help
python generate_api_key.py https://meta.discourse.org
"""
import argparse
from base64 import b64decode
import json
from secrets import token_urlsafe
from urllib.parse import urlencode
from Cryptodome.Cipher import PKCS1_v1_5
from Cryptodome.PublicKey import RSA
from Cryptodome.Random import get_random_bytes
def generate_api_key(host):
# generate RSA key
key = RSA.generate(2048)
# assemble the url
path = "/user-api-key/new"
query_dict = {
"application_name": "python",
"client_id": token_urlsafe(),
"scopes": "read",
"public_key": key.publickey().export_key().decode(),
"nonce": 1,
}
query = urlencode(query_dict)
url = f"{host}{path}?{query}"
print(f"Navigate to {url} and copy the generated ciphertext in here:\n")
ciphertext = input()
# process the ciphertext from discourse
sentinel = get_random_bytes(16)
cipher_rsa = PKCS1_v1_5.new(key)
plaintext = cipher_rsa.decrypt(b64decode(ciphertext), sentinel)
plaintext = json.loads(plaintext.decode())
return plaintext["key"]
def main():
parser = argparse.ArgumentParser()
parser.add_argument("host", type=str, help="Hostname of the discourse server.")
args = parser.parse_args()
api_key = generate_api_key(args.host)
print("\nUser API key:", api_key)
if __name__ == "__main__":
main()
@printmaps
Copy link

I tried this (public key shortened) ...

https://community.openstreetmap.org/user-api-key/new?application_name=python&client_id=my_pc&scopes=read&public_key=-----BEGIN+PUBLIC+KEY-----MissingData-----END+PUBLIC+KEY-----&nonce=1

Bildschirmfoto 2022-10-29 um 09 24 25

... and got that:

Bildschirmfoto 2022-10-29 um 09 24 42

Question: How to find out what's going on?

PS: Same result for "meta.discourse.org".

@marph91
Copy link
Author

marph91 commented Oct 29, 2022

I just tried to reproduce, but it works for me (Ubuntu 22.04 + Firefox). I can't see the issue in your description, though. The link seems to work and you are logged in. Else you wouldn't get to the "Genehmigen" button.

The second screenshot suggests that it is an internal error. Could you try again after some time? (The fact that the error is happening on two distinct discourse servers does still look like another problem to me.)

@printmaps
Copy link

I tried it from macOS with fresh installed python and pycryptodomex:

macOS: 12.6.1
python: 3.10.8
pycryptodomex: 3.15.0

An alternative tests via this site "https://observablehq.com/@beanow/generate-user-api-key-for-discourse" worked for me without any problems.

BTW: I want to write my own Discourse-User-API-Key client with Go. For this purposes this script seems to be a good blueprint.

@marph91
Copy link
Author

marph91 commented Oct 29, 2022

It might be something handled differently on mac (maybe the key is somehow not correct at the URL). I'm using python 3.10.6 and pycryptodomex 3.15.0. The versions seem to be no issue. Since I don't have a mac, it will be difficult to debug for me.

Note: The python script is also only a migration of this (ruby?) script.

@call-me-matt
Copy link

same problem here.
the problem is the client_id. This is how to fix it:
image

@marph91
Copy link
Author

marph91 commented Jan 3, 2023

Thanks for investigating and providing the fix @call-me-matt! I updated the script.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment