Skip to content

Repo containing the configuration to build and test a freshrss oci image

Notifications You must be signed in to change notification settings

batinicaz/freshrss-oci

Repository files navigation

freshrss-oci

Uses packer and Ansible to create a custom image for use in Oracle Cloud Infrastructure (OCI).

Built on latest Ubuntu 24.04 OCI image. Builds every day at 3AM.

Includes the following applications:

  • 🗞️ FreshRSS for feed reading
  • 🔎 FullTextRSS for converting partial feeds into full feeds for use in FreshRSS
  • 🐦 Nitter for providing RSS feeds for Twitter
  • 👽 Redlib for browsing Reddit
  • 🗂️ Planka for task management
  • 🌐 OpenResty to serve FreshRSS and reverse proxy to other services with support for OIDC auth.
  • 🔐 Tailscale for management (SSH removed)

Along with the following config tweaks:

  • 📦 All packages updated
  • 🦾 AppArmor configured with appropriate profiles
  • 🕐 CRON jobs to automatically backup FreshRSS and update FreshRSS feeds
  • ⏪ Custom restore script to support restoring the CRON created backups
  • 🚫 iptables configured to limit allowed ingress
  • 🗄️ Latest site configs mapped into FullTextRSS container
  • 🧹 Log rotate configured for all services
  • 🔕 MOTD advertisements/spam removed
  • 🧰 OCI CLI added
  • 📊 Oracle cloud agent added
  • 🙅 Ubuntu Advantage removed
  • 🕵️ Telemetry packages removed and telemetry domains blocked
  • 🤖 Nginx configured to prevent site being scraped by bots

Deployment

Deployed via Terraform, see: batinicaz/freshrss

Nitter Guest Accounts

Nitter requires a real account due to Twitters recent API changes and removal of guest accounts.

Thanks to 983 you can generate a suitable token by setting the username/password and then using the Python snippet below:

import requests

username=""
password=""

authentication = None

session = requests.session()

authorization_bearer = 'Bearer AAAAAAAAAAAAAAAAAAAAAFXzAwAAAAAAMHCxpeSDG1gLNLghVe8d74hl6k4%3DRUMF4xAQLsbeBhTSRrCiQpJtxoGWeyHrDb5te2jpGskWDFW82F'
guest_token = requests.post("https://api.twitter.com/1.1/guest/activate.json", headers={'Authorization': authorization_bearer}).json()['guest_token']

headers = {
    'X-Guest-Token': guest_token,
    'Content-Type': 'application/json',
    'Authorization':  authorization_bearer
}
session.headers.update(headers)

task1 = session.post('https://api.twitter.com/1.1/onboarding/task.json',
    params={
        'flow_name': 'login',
        'api_version': '1',
        'known_device_token': '',
        'sim_country_code': 'us'
    },
    json={
        "flow_token": None,
        "input_flow_data": {
            "country_code": None,
            "flow_context": {
                "referrer_context": {
                    "referral_details": "utm_source=google-play&utm_medium=organic",
                    "referrer_url": ""
                },
                "start_location": {
                    "location": "deeplink"
                }
            },
            "requested_variant": None,
            "target_user_id": 0
        }
    }
)

session.headers['att'] = task1.headers.get('att')
task2 = session.post('https://api.twitter.com/1.1/onboarding/task.json', json={
    "flow_token": task1.json().get('flow_token'),
    "subtask_inputs": [{
            "enter_text": {
                "suggestion_id": None,
                "text": username,
                "link": "next_link"
            },
            "subtask_id": "LoginEnterUserIdentifier"
        }
    ]
})

task3 = session.post('https://api.twitter.com/1.1/onboarding/task.json', json={
    "flow_token": task2.json().get('flow_token'),
    "subtask_inputs": [{
            "enter_password": {
                "password": password,
                "link": "next_link"
            },
            "subtask_id": "LoginEnterPassword"
        }
    ],
})

task4 = session.post('https://api.twitter.com/1.1/onboarding/task.json', json={
    "flow_token": task3.json().get('flow_token'),
    "subtask_inputs": [{
            "check_logged_in_account": {
                "link": "AccountDuplicationCheck_false"
            },
            "subtask_id": "AccountDuplicationCheck"
        }
    ]
}).json()

for t4_subtask in task4.get('subtasks', []):
    if 'open_account' in t4_subtask:
        authentication = t4_subtask['open_account']
        break
    elif 'enter_text' in t4_subtask:
        response_text = t4_subtask['enter_text']['hint_text']
        code = input(f'Requesting {response_text}: ')
        task5 = session.post('https://api.twitter.com/1.1/onboarding/task.json', json={
            "flow_token": task4.get('flow_token'),
            "subtask_inputs": [{
                "enter_text": {
                    "suggestion_id": None,
                    "text": code,
                    "link": "next_link"
                },
                "subtask_id": "LoginAcid"
            }]
        }).json()
        for t5_subtask in task5.get('subtasks', []):
            if 'open_account' in t5_subtask:
                authentication = t5_subtask['open_account']

print(authentication)
{
    'attribution_event': 'login',
    'known_device_token': 'XXXXXXXXXXXXXXXXXXXXXX',
    'next_link': {
        'link_id': 'next_link',
        'link_type': 'subtask',
        'subtask_id': 'SuccessExit'
    },
    'oauth_token': 'XXXXXXXXXXXXXXXXXXXXXX',
    'oauth_token_secret': 'XXXXXXXXXXXXXXXXXXXXXX',
    'user': {
        'id': 'XXXXXXXXXXXXXXXXXXXXXX',
        'id_str': 'XXXXXXXXXXXXXXXXXXXXXX',
        'name': 'XXXXXXXXXXXXXXXXXXXXXX',
        'screen_name': 'XXXXXXXXXXXXXXXXXXXXXX'
    }
}

This then enables you to use Nitter on the guest_accounts branch provided the 30 day expiry is disabled (https://github.com/batinicaz/nitter/commit/acc2b906668e5dd405a3a1453250c3a873db7220).

About

Repo containing the configuration to build and test a freshrss oci image

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published