Created
November 9, 2022 16:19
-
-
Save NeKzor/e7d8551c4f55fbe4ec16252e0f6fa012 to your computer and use it in GitHub Desktop.
Simple Mastodon bot in 100 lines.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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