Skip to content

Instantly share code, notes, and snippets.

@NeKzor
Created November 9, 2022 16:19
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NeKzor/e7d8551c4f55fbe4ec16252e0f6fa012 to your computer and use it in GitHub Desktop.
Save NeKzor/e7d8551c4f55fbe4ec16252e0f6fa012 to your computer and use it in GitHub Desktop.
Simple Mastodon bot in 100 lines.
const fetch = require('node-fetch');
const createHiddenField = (obj, fieldName, value) => {
Object.defineProperty(obj, fieldName, {
enumerable: false,
writable: true,
value: value,
});
};
class MastodonClient {
constructor(client_key, client_secret) {
if (!client_key) throw new Error('client key is requuired');
if (!client_secret) throw new Error('client secret is required');
this.baseUrl = 'https://techhub.social';
this.userAgent = 'nekzbot';
this.loginData = null;
this.client_key = client_key;
createHiddenField(this, 'client_secret', client_secret);
}
authorizationUrl() {
return `${this.baseUrl}/oauth/authorize?response_type=code&client_id=${this.client_key}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=write`;
}
async login(code) {
const data = {
grant_type: code ? 'authorization_code' : 'client_credentials',
client_id: this.client_key,
client_secret: this.client_secret,
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
scope: 'write',
code,
};
const res = await fetch(`${this.baseUrl}/oauth/token`, {
method: 'POST',
headers: {
'User-Agent': this.userAgent,
'Content-Type': 'application/x-www-form-urlencoded',
},
body: Object.entries(data)
.filter((x) => x)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join('&'),
});
this.loginData = await res.json();
return this;
}
async publishStatus(status) {
const token = this.loginData?.access_token;
if (!token) throw Error('not logged in');
const data = {
status,
};
const res = await fetch(`${this.baseUrl}/api/v1/statuses`, {
method: 'POST',
headers: {
'User-Agent': this.userAgent,
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + token,
},
body: Object.entries(data)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join('&'),
});
const json = await res.json();
return this;
}
}
async function main() {
const client = new MastodonClient(
'CLIENT KEY',
'CLIENT SECRET',
);
const stdin = process.openStdin();
process.stdout.write(`Authorize Mastodon Client: ${client.authorizationUrl()}\n\nEnter Authorization Code: `);
stdin.addListener('data', async (text) => {
const code = text.toString().trim();
console.log('[mastodon] Logging in...');
stdin.pause();
await client.login(code);
console.log('[mastodon] Logged in');
await client.publishStatus(':^)');
});
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment