Autoinstall fediblockhole
This commit is contained in:
parent
5eb228c279
commit
a5f1e6b711
6 changed files with 249 additions and 0 deletions
|
@ -8,6 +8,7 @@ The intent here is to create an all-in-one social server build
|
||||||
* AWS CLI
|
* AWS CLI
|
||||||
* AWS SessionManager plugin (http://docs.aws.amazon.com/console/systems-manager/session-manager-plugin-not-found)
|
* AWS SessionManager plugin (http://docs.aws.amazon.com/console/systems-manager/session-manager-plugin-not-found)
|
||||||
* Python 3.6+ for credentials
|
* Python 3.6+ for credentials
|
||||||
|
* python3-bs4 (BeautifulSoup 4)
|
||||||
|
|
||||||
Your AWS account needs to be moved from the SES sandbox into production in the region you're deploying to. This is
|
Your AWS account needs to be moved from the SES sandbox into production in the region you're deploying to. This is
|
||||||
requested through the AWS console.
|
requested through the AWS console.
|
||||||
|
|
80
ansible/roles/fediblockhole/bin/get_token.py
Executable file
80
ansible/roles/fediblockhole/bin/get_token.py
Executable file
|
@ -0,0 +1,80 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys,requests
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
|
# Generate an app token for fediblockhole.
|
||||||
|
|
||||||
|
# Mastodon has opted not to expose admin tasks like this in any way that can be automated easily.
|
||||||
|
|
||||||
|
# This whole thing is a house of cards that will topple as soon as Mastodon's UI changes,
|
||||||
|
# which is often. It's a bad idea and I regret doing it. Anyway, enjoy.
|
||||||
|
|
||||||
|
# args are simple:
|
||||||
|
# - server domain
|
||||||
|
# - app name
|
||||||
|
# - admin email
|
||||||
|
# - path to password file
|
||||||
|
|
||||||
|
try:
|
||||||
|
domain = sys.argv[1]
|
||||||
|
appname = sys.argv[2]
|
||||||
|
email = sys.argv[3]
|
||||||
|
pwpath = sys.argv[4]
|
||||||
|
except IndexError:
|
||||||
|
print(f"Usage: {sys.argv[0]} domain email path_to_password_file")
|
||||||
|
|
||||||
|
password = ""
|
||||||
|
with open(pwpath) as fh:
|
||||||
|
password = fh.read()
|
||||||
|
|
||||||
|
with requests.Session() as session:
|
||||||
|
|
||||||
|
session.max_redirects = 10
|
||||||
|
|
||||||
|
# log in first
|
||||||
|
r = session.get(f"https://{domain}/auth/sign_in")
|
||||||
|
soup = BeautifulSoup(r.text, "html.parser")
|
||||||
|
|
||||||
|
form = soup.find("form")
|
||||||
|
assert form.get("action") == "/auth/sign_in"
|
||||||
|
params = {}
|
||||||
|
|
||||||
|
for field in form.find_all("input"):
|
||||||
|
params[field.get("name")] = field.get("value")
|
||||||
|
|
||||||
|
params["user[email]"] = email
|
||||||
|
params["user[password]"] = password
|
||||||
|
|
||||||
|
r = session.post(f"https://{domain}{form.get('action')}", data=params)
|
||||||
|
|
||||||
|
assert r.status_code == 200
|
||||||
|
|
||||||
|
r = session.get(f"https://{domain}/settings/applications/new")
|
||||||
|
|
||||||
|
soup = BeautifulSoup(r.text, "html.parser")
|
||||||
|
form = soup.find("form")
|
||||||
|
|
||||||
|
params = {}
|
||||||
|
for field in form.find_all("input"):
|
||||||
|
params[field.get("name")] = field.get("value")
|
||||||
|
for field in form.find_all("textarea"):
|
||||||
|
params[field.get("name")] = field.get("value")
|
||||||
|
|
||||||
|
params["doorkeeper_application[name]"] = appname
|
||||||
|
params["doorkeeper_application[website]"] = f"https://{domain}/"
|
||||||
|
params["doorkeeper_application[redirect_uri]"] = "urn:ietf:wg:oauth:2.0:oob"
|
||||||
|
params["doorkeeper_application[scopes][]"] = [ "admin:read", "admin:write" ]
|
||||||
|
|
||||||
|
r = session.post(f"https://{domain}{form.get('action')}", data=params)
|
||||||
|
|
||||||
|
soup = BeautifulSoup(r.text, "html.parser")
|
||||||
|
search = soup.find_all(lambda x: x.name == "a" and x.text == appname)
|
||||||
|
|
||||||
|
tag = search[0] # we will just take the first one
|
||||||
|
r = session.get(f"https://{domain}{tag['href']}")
|
||||||
|
|
||||||
|
soup = BeautifulSoup(r.text, "html.parser")
|
||||||
|
tag = soup.find_all(lambda x: x.text == "Your access token")[0]
|
||||||
|
print(tag.find_next('code').text)
|
||||||
|
|
82
ansible/roles/fediblockhole/tasks/main.yaml
Normal file
82
ansible/roles/fediblockhole/tasks/main.yaml
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- name: install base apps
|
||||||
|
apt:
|
||||||
|
force_apt_get: yes
|
||||||
|
name:
|
||||||
|
- python3-pip
|
||||||
|
|
||||||
|
- name: base path
|
||||||
|
file:
|
||||||
|
path: "/etc/fediblockhole/blocklists"
|
||||||
|
state: directory
|
||||||
|
recurse: true
|
||||||
|
|
||||||
|
- name: install/upgrade fediblockhole
|
||||||
|
command: python3 -m pip install --upgrade fediblockhole
|
||||||
|
|
||||||
|
#- name: install/upgrade Mastodon.py
|
||||||
|
# command: python3 -m pip install --upgrade Mastodon.py
|
||||||
|
|
||||||
|
- name: ensure our domain is in the safelist
|
||||||
|
lineinfile:
|
||||||
|
path: /etc/fediblockhole/safelist.csv
|
||||||
|
create: true
|
||||||
|
line: "{{ domain_name }}"
|
||||||
|
|
||||||
|
- name: check fediblockhole API credentials
|
||||||
|
delegate_to: localhost
|
||||||
|
become: false
|
||||||
|
stat:
|
||||||
|
path: credentials/fediblockhole/token
|
||||||
|
register: token_file
|
||||||
|
|
||||||
|
- name: generate a fediblockhole token
|
||||||
|
block:
|
||||||
|
|
||||||
|
- name: make fediblockhole credentials dir
|
||||||
|
delegate_to: localhost
|
||||||
|
become: false
|
||||||
|
file:
|
||||||
|
path: "credentials/fediblockhole"
|
||||||
|
state: directory
|
||||||
|
recurse: true
|
||||||
|
|
||||||
|
- name: request app token
|
||||||
|
delegate_to: localhost
|
||||||
|
become: false
|
||||||
|
command: roles/fediblockhole/bin/get_token.py {{ domain_name }} fediblockhole {{ admin_email }} credentials/mastodon/masto_admin_pw
|
||||||
|
register: apptoken
|
||||||
|
|
||||||
|
- name: write token to file
|
||||||
|
delegate_to: localhost
|
||||||
|
become: false
|
||||||
|
copy:
|
||||||
|
dest: credentials/fediblockhole/token
|
||||||
|
content: "{{ apptoken.stdout }}"
|
||||||
|
|
||||||
|
when: token_file.stat.exists != true
|
||||||
|
|
||||||
|
- name: pull config file
|
||||||
|
template:
|
||||||
|
src: templates/pull.conf.toml
|
||||||
|
dest: /etc/fediblockhole/pull.conf.toml
|
||||||
|
|
||||||
|
- name: push config file
|
||||||
|
template:
|
||||||
|
src: templates/push.conf.toml
|
||||||
|
dest: /etc/fediblockhole/push.conf.toml
|
||||||
|
vars:
|
||||||
|
token: "{{ lookup('ansible.builtin.file', 'credentials/fediblockhole/token') }}"
|
||||||
|
|
||||||
|
- name: daily cron file
|
||||||
|
copy:
|
||||||
|
dest: /etc/cron.daily/fediblockhole
|
||||||
|
mode: '0755'
|
||||||
|
content: |
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
/usr/local/bin/fediblock-sync -c /etc/fediblockhole/pull.conf.toml
|
||||||
|
/usr/local/bin/fediblock-sync -c /etc/fediblockhole/push.conf.toml
|
||||||
|
|
40
ansible/roles/fediblockhole/templates/pull.conf.toml
Normal file
40
ansible/roles/fediblockhole/templates/pull.conf.toml
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
blocklist_instance_sources = [
|
||||||
|
# { domain = 'mastodon.social'},
|
||||||
|
# { domain = 'union.place'},
|
||||||
|
]
|
||||||
|
|
||||||
|
blocklist_url_sources = [
|
||||||
|
# some oliphant CSV blocklist files - you only need one "tier" file
|
||||||
|
{ url = 'https://codeberg.org/oliphant/blocklists/raw/branch/main/blocklists/_unified_tier0_blocklist.csv', format = 'csv' },
|
||||||
|
#{ url = 'https://codeberg.org/oliphant/blocklists/raw/branch/main/blocklists/_unified_tier1_blocklist.csv', format = 'csv' },
|
||||||
|
#{ url = 'https://codeberg.org/oliphant/blocklists/raw/branch/main/blocklists/_unified_tier2_blocklist.csv', format = 'csv' },
|
||||||
|
#{ url = 'https://codeberg.org/oliphant/blocklists/raw/branch/main/blocklists/_unified_tier3_blocklist.csv', format = 'csv' },
|
||||||
|
#{ url = 'https://codeberg.org/oliphant/blocklists/raw/branch/main/blocklists/oliphant.social.csv', format = 'csv' },
|
||||||
|
]
|
||||||
|
|
||||||
|
# reference your safelist
|
||||||
|
allowlist_url_sources = [
|
||||||
|
{ url = 'file:///etc/fediblockhole/safelist.csv', format = 'csv' },
|
||||||
|
]
|
||||||
|
|
||||||
|
# this file isn't going to push to an instance
|
||||||
|
no_push_instance = true
|
||||||
|
|
||||||
|
# Store a local copy of the remote blocklists after we fetch them
|
||||||
|
# set to true if you want (optional)
|
||||||
|
save_intermediate = false
|
||||||
|
|
||||||
|
## Directory to store the local blocklist copies
|
||||||
|
savedir = '/etc/fediblockhole/blocklists'
|
||||||
|
|
||||||
|
## File to save the fully merged blocklist into
|
||||||
|
blocklist_savefile = '/etc/fediblockhole/blocklists/merged_blocklist.csv'
|
||||||
|
|
||||||
|
mergeplan = 'max'
|
||||||
|
|
||||||
|
# merge must match at least [count|pct] sources
|
||||||
|
# merge_threshold_type = 'count'
|
||||||
|
# merge_threshold = 0
|
||||||
|
|
||||||
|
import_fields = ['reject_media', 'reject_reports', 'public_comment', 'private_comment', 'obfuscate']
|
||||||
|
export_fields = ['reject_media', 'reject_reports', 'public_comment', 'private_comment', 'obfuscate']
|
45
ansible/roles/fediblockhole/templates/push.conf.toml
Normal file
45
ansible/roles/fediblockhole/templates/push.conf.toml
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
blocklist_instance_sources = [
|
||||||
|
# { domain = 'mastodon.social'},
|
||||||
|
# { domain = 'union.place'},
|
||||||
|
]
|
||||||
|
|
||||||
|
blocklist_url_sources = [
|
||||||
|
# some oliphant CSV blocklist files - you only need one "tier" file
|
||||||
|
{ url = 'https://codeberg.org/oliphant/blocklists/raw/branch/main/blocklists/_unified_tier0_blocklist.csv', format = 'csv' },
|
||||||
|
#{ url = 'https://codeberg.org/oliphant/blocklists/raw/branch/main/blocklists/_unified_tier1_blocklist.csv', format = 'csv' },
|
||||||
|
#{ url = 'https://codeberg.org/oliphant/blocklists/raw/branch/main/blocklists/_unified_tier2_blocklist.csv', format = 'csv' },
|
||||||
|
#{ url = 'https://codeberg.org/oliphant/blocklists/raw/branch/main/blocklists/_unified_tier3_blocklist.csv', format = 'csv' },
|
||||||
|
#{ url = 'https://codeberg.org/oliphant/blocklists/raw/branch/main/blocklists/oliphant.social.csv', format = 'csv' },
|
||||||
|
]
|
||||||
|
|
||||||
|
# reference your safelist
|
||||||
|
allowlist_url_sources = [
|
||||||
|
{ url = 'file:///etc/fediblockhole/safelist.csv', format = 'csv' },
|
||||||
|
]
|
||||||
|
|
||||||
|
# this file isn't going to push to an instance
|
||||||
|
no_push_instance = false
|
||||||
|
|
||||||
|
# Store a local copy of the remote blocklists after we fetch them
|
||||||
|
# set to true if you want (optional)
|
||||||
|
save_intermediate = false
|
||||||
|
|
||||||
|
## Directory to store the local blocklist copies
|
||||||
|
savedir = '/etc/fediblockhole/blocklists'
|
||||||
|
|
||||||
|
## File to save the fully merged blocklist into
|
||||||
|
blocklist_savefile = '/etc/fediblockhole/blocklists/merged_blocklist.csv'
|
||||||
|
|
||||||
|
mergeplan = 'max'
|
||||||
|
|
||||||
|
# merge must match at least [count|pct] sources
|
||||||
|
# merge_threshold_type = 'count'
|
||||||
|
# merge_threshold = 0
|
||||||
|
|
||||||
|
import_fields = ['reject_media', 'reject_reports', 'public_comment', 'private_comment', 'obfuscate']
|
||||||
|
export_fields = ['reject_media', 'reject_reports', 'public_comment', 'private_comment', 'obfuscate']
|
||||||
|
|
||||||
|
blocklist_instance_destinations = [
|
||||||
|
{ domain = '{{ domain_name }}', token = '{{ token }}', max_followed_severity = 'silence'},
|
||||||
|
]
|
||||||
|
|
|
@ -11,4 +11,5 @@
|
||||||
- { role: certbot, become: yes }
|
- { role: certbot, become: yes }
|
||||||
- { role: nginx, become: yes }
|
- { role: nginx, become: yes }
|
||||||
- { role: mastodon, become: yes }
|
- { role: mastodon, become: yes }
|
||||||
|
- { role: fediblockhole, become: yes }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue