#!/usr/bin/env python3
# localslackirc
# Copyright (C) 2024 Salvo "LtWorf" Tomaselli
#
# localslackirc is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# author Salvo "LtWorf" Tomaselli <tiposchi@tiscali.it>

import os
import sys
import sqlite3
import argparse
from pathlib import Path


HOME = Path(os.environ.get('HOME', ''))
MOZILLA_CONF = HOME / '.mozilla'

def log(*args):
    print(*args, file=sys.stderr)

def get_mozilla_localstorage_tokens(ls: Path) -> list[str]:
    '''
    Pass the path of a possible local storage file and get slack tokens
    '''

    db = sqlite3.connect(ls)
    try:
        s = db.execute('select value from data where key="localConfig_v2";')
    except Exception:
        return []

    r = []
    for i in s:
        # Some magic crap, it's a readable json polluted with unreadable crap…
        # No idea if this will work in other cases than on my machine

        i = i[0]
        i = i.split(b'"toke', 1)[1].split(b'"', 1)[0]
        i = i[i.index(b'xox'):]
        r.append(i.decode('ascii'))

    return r


def get_mozilla_cookies(jar: Path) -> list[str]:
    '''
    Pass the path of a cookie jar and receive a list of slack cookies
    '''
    db = sqlite3.connect(jar)
    return [i[0] for i in db.execute('select value from moz_cookies WHERE host= ".slack.com" and name="d";')]

def mozilla(cfgdir: Path) -> tuple[list[str], list[str]]:
    '''
    returns cookies, tokens
    '''
    log(f'Scanning {cfgdir} as a Mozilla directory')
    cookiefiles = cfgdir.rglob('cookies.sqlite')
    other_files = cfgdir.rglob('*.sqlite')

    cookies = []
    tokens = []

    for i in cookiefiles:
        log(f'Scanning possible cookie jar {i}')
        try:
            cookies += get_mozilla_cookies(i)
        except Exception as e:
            sys.exit(str(e))

    for i in other_files:
        log(f'Scanning possible local storage file {i}')
        try:
            tokens += get_mozilla_localstorage_tokens(i)
        except Exception as e:
            sys.exit(str(e))

    return cookies, tokens

def main() -> None:
    parser = argparse.ArgumentParser(
        description='Read the browser database to try to find the cookie and token that are necessary to set up localslackirc.'
    )
    parser.add_argument('--mozilla-dir', type=Path, action='store', dest='mozilla_dir',
                                default=MOZILLA_CONF)
    args = parser.parse_args()

    cookies = []
    tokens = []

    c, t = mozilla(args.mozilla_dir)
    cookies += c
    tokens += t

    # TODO chromium

    if not cookies and not tokens:
        sys.exit('Fail: Nothing was found')

    print('# ==============')
    if tokens:
        print('# Tokens found:')
    for i in tokens:
        print(f'TOKEN={i}')
    if cookies:
        print('# Cookies found:')
    for i in cookies:
        print(f'COOKIE="d={i};"')

    if len(tokens) > 1 or len(cookies) > 1:
        print('# Try deleting all cookies from your browsers and logging into slack again')

if __name__ == '__main__':
    main()
