Compare commits

..

No commits in common. "48f94ad8ad9524357d24ad3073f39cc69468beb3" and "b772f8aeaf0e42dc1764fa0945e4ef9d56ebb908" have entirely different histories.

3 changed files with 27 additions and 142 deletions

View File

@ -1,40 +1,3 @@
# gotosocial
## GoToSocial
A library for building GoToSocial bots
## client
This is a variant on my Mastodon bot code and hasn't been properly tested yet: I'll document it when I've done that.
## register
A utility for making it easier to register an app and get an access token for
a GoToSocial account - it's a Python script which automates as much of [the client API instructions](https://docs.gotosocial.org/en/latest/api/authentication/) as possible. There's still some manual stuff required for authenticating.
This project is maintained with [uv](https://docs.astral.sh/uv/): install it, check out this repo and then you can run the script with the uv commands below and it should take care of dependencies.
To register an app, you first need to give it an identity on the server - in the examples I've called the server `https://your.server/` and the app `mybot`
uv run register -u https://your.server/ -n mybot
This will create an app on the server and write out the client id and secret to a file in the current directory called `mybot_app.json`. It will also write a URL to the command line for the next step
The second step is to visit that URL in an incognito browser window. You'll be prompted to authenticate - use the email address and password for the GoToSocial account which you want to post to via the app.
Once you authenticate, you should be taken to a page which has a message like:
Hi account!
Here's your out-of-band token with scope "write", use it wisely:
ABIGLONGSTRINGOFLETTERSANDNUMBERS
Copy the out-of-band token and do the third step straight away, as the token will expire.
The third step exchanges the above token for a permanent access token, by running the script again in the same directory, passing the OOB token with the -t flag:
uv run register -u https://your.server/ -n mybot -t ABIGLONGSTRINGOFLETTERSANDNUMBERS
If this is successful, your access token - another, different string of letters and numbers - will be printed to the command prompt. The access token is also written out as a json file with the name `mybot_at.json`.
You should now be able to use the access token to post to your GoToSocial account.
Putting together some client code for working with GoToSocial in Python

View File

@ -11,9 +11,6 @@ dependencies = [
"requests>=2.32.3",
]
[project.scripts]
register = "gotosocial.register:cli"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

View File

@ -1,112 +1,37 @@
# script to register an API
import requests
from pathlib import Path
import json
import argparse
class Application:
def __init__(self, base_url, name, scopes="write"):
def __init__(self, base_url, name):
self.base_url = base_url
self.name = name
self.scopes = scopes
self.headers = {"Content-Type": "application/json"}
def register(self):
app_json = Path(f"./{self.name}_app.json")
if app_json.is_file():
print(f"Found {app_json} file")
print(f"Looks like you've already registered {self.name}")
return False
data = {
"client_name": self.name,
"redirect_uris": "urn:ietf:wg:oauth:2.0:oob",
"scopes": self.scopes,
}
try:
response = requests.post(
f"{self.base_url}/api/v1/apps",
data=json.dumps(data),
headers=self.headers,
)
response.raise_for_status()
json_r = response.json()
self.client_id = json_r["client_id"]
self.client_secret = json_r["client_secret"]
print(f"Registered {self.name}, client ID is {self.client_id}")
with open(app_json, "w") as jfh:
json.dump(json_r, jfh, indent=2)
print(f"Wrote response to {app_json}")
auth_url = f"{self.base_url}/oauth/authorize?client_id={self.client_id}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope={self.scopes}"
print("Visit this URL in a private browser window to authenticate:")
print(auth_url)
print("\nThen run this script again with the OOB token, like:")
print("> uv run register -u {self.base_ur} -n {self.name} -t OOB_TOKEB")
return True
except Exception as e:
print("Something went wrong:")
print(e)
return False
def get_auth_token(self, token):
app_json = Path(f"./{self.name}_app.json")
if not app_json.is_file():
print(f"No {app_json} file found")
print("You need to register the app before getting a token")
return False
try:
with open(app_json, "r") as jfh:
cf = json.load(jfh)
data = {
"client_id": cf["client_id"],
"client_secret": cf["client_secret"],
"redirect_uri": "urn:ietf:wg:oauth:2.0:oob",
"grant_type": "authorization_code",
"code": token,
}
response = requests.post(
f"{self.base_url}/oauth/token",
data=json.dumps(data),
headers=self.headers,
)
response.raise_for_status()
json_r = response.json()
access_token = json_r["access_token"]
print(f"Got access token: {access_token}")
at_json = self.unique_at_file()
with open(at_json, "w") as jfh:
json.dump(json_r, jfh, indent=2)
print(f"Wrote response to {at_json}")
except Exception as e:
print("Something went wrong:")
print(e)
print("Note that this may be because your OOB token has expired")
return False
def unique_at_file(self):
fn = f"./{self.name}_at.json"
n = 0
while Path(fn).is_file():
print(f"File {fn} already exists")
n += 1
fn = f"./{self.name}_at_{n}.json"
return fn
def register_app(self):
response = requests.post(
f"{self.base_url}/api/v1/statuses",
data={
"client_name": self.name,
"redirect_uris": "urn:ietf:wg:oauth:2.0:oob",
"scopes": "write",
},
headers=self.headers,
)
response.raise_for_status()
json_r = response.json()
self.client_id = json_r["client_id"]
self.client_secret = json_r["client_secret"]
print(f"Registered {self.name} as {self.client_id}")
def cli():
ap = argparse.ArgumentParser()
ap.add_argument("-u", "--url", required=True, type=str, help="GoToSocial server")
ap.add_argument("-n", "--name", required=True, type=str, help="Application name")
ap.add_argument("-s", "--scopes", default="write", type=str, help="Scope")
ap.add_argument("-t", "--token", type=str, help="OOB token")
args = ap.parse_args()
app = Application(args.url, args.name, args.scopes)
if args.token:
app.get_auth_token(args.token)
else:
app.register()
if __name__ == "__main__":
cli()
# curl \
# -X POST \
# -H 'Content-Type:application/json' \
# -d '{
# "client_name": "your_app_name",
# "redirect_uris": "urn:ietf:wg:oauth:2.0:oob",
# "scopes": "read"
# }' \
# 'https://example.org/api/v1/apps'