***无法从/opt/tortoisehg/cookie-auth/cookie-auth.py导入扩展cookie-auth:'gi.repository.GLib'

时间:2019-11-27 06:55:58

标签: python python-3.x cookies pygobject

我有一个针对mercurial的以公司为中心的扩展程序,该扩展程序在python2 mercurial 5.0.x中工作,现在已使用python3 + mercurial 5.2破坏了。该扩展程序查看用于登录我们的存储库的Chrome cookie并使用它进行身份验证。

Arch Linux:4.19.86-1-lts 的Python:3.8.0 水银:5.2

如果我自己运行脚本,即python <script name>可以正常运行,也就是说它不会引发任何错误。但是,当我尝试打开tortoisehg甚至运行基本的hg命令时,例如hg push会输出如下错误:

  

***无法从/opt/tortoisehg/cookie-auth/cookie-auth.py导入扩展cookie-auth:'gi.repository.GLib'

已安装系统软件包(Arch Linux) -python-gobject -pygobject-devel -还安装了gtk3和lib32-gtk3

已安装的pip软件包: -pygobject -gobject

也许是pygobject的问题,因为如果我删除该行:

from gi.repository import Secret

然后脚本一直运行到第一次提到“秘密”时,该脚本将引发错误并崩溃。

还:是的,扩展名已添加到我的.hgrc文件中

这是扩展文件:

#!/usr/bin/env python

import sqlite3
from http.cookiejar import CookieJar, MozillaCookieJar, Cookie
from urllib.request import Request
import urllib

import webbrowser

from mercurial.i18n import _
import mercurial.url
from mercurial import commands
from mercurial import cmdutil

import inspect
import os
import sys
from urllib.parse import urlparse
import tempfile
import glob
import json
import platform

if platform.system() == 'Linux':
        from Crypto.Cipher import AES
        from Crypto.Protocol.KDF import PBKDF2
        import keyring

        import gi
        gi.require_version('Secret', '1')
        from gi.repository import Secret

testedwith = '3.9'

# Function to get rid of padding
def clean(x): 
        return x[:-ord(x[-1])].decode('utf8')

class BrowserCookieError(Exception):
        pass

def create_local_copy(cookie_file):
        """Make a local copy of the sqlite cookie database and return the new filename.
        This is necessary in case this database is still being written to while the user browses
        to avoid sqlite locking errors.
        """
        # if type of cookie_file is a list, use the first element in the list
        if isinstance(cookie_file, list):
                cookie_file = cookie_file[0]

        # check if cookie file exists
        if os.path.exists(cookie_file):
                # copy to random name in tmp folder
                tmp_cookie_file = tempfile.NamedTemporaryFile(suffix='.sqlite').name
                open(tmp_cookie_file, 'wb').write(open(cookie_file, 'rb').read())
                return tmp_cookie_file
        else:
                raise BrowserCookieError('Can not find cookie file at: ' + cookie_file)

class Chrome:
        def get_cookies(self, request, ui):
            domain = request.get_host()
            port = None
            if ':' in domain:
                domain, port = domain.split(':', 1)
            if '.' not in domain:
                domain += ".local"

            #platform specific file / config options
            jar = ""
            iterations = 1
            my_pass = ""
            if platform.system() == 'Linux':
                jar = "/home/access/.config/chromium/Default/Cookies"
                print(jar)
                #jar = os.path.expanduser("~/.config/chromium/Default/Cookies")

                #libsecret from chrome 55 onwards (I think)
                CHROME_SCHEMA_V2 = Secret.Schema.new(
                        "chrome_libsecret_os_crypt_password_v2",
                        Secret.SchemaFlags.DONT_MATCH_NAME,
                        {
                            "application": Secret.SchemaAttributeType.STRING,
                        }
                )
                #my_pass = Secret.password_lookup_sync(CHROME_SCHEMA_V2, { "application" : "chromium" }, None)

                #old fixed password
                my_pass = "peanuts"
                #not sure why this doesn't work
                #passw = keyring.get_password('Chrome Safe Storage', '')

            try:
                conn = sqlite3.connect(jar)
                print(conn)
            except Error as e:
                print(e)

            c = conn.cursor()

            try:
                c.execute(" SELECT name,path,is_secure,value,encrypted_value FROM cookies WHERE host_key='<host key>'")
                #c.execute("SELECT name,path,secure,value,encrypted_value FROM cookies WHERE host_key='%s'" % domain)
                rows = c.fetchall()
            except sqlite3.OperationalError as e:
                print(e)
                #c.execute("SELECT * FROM cookies")
                #c.execute("SELECT name,path,is_secure,value,encrypted_value FROM cookies WHERE host_key='%s'" % domain)
                rows = c.fetchall()

            req_type = request.get_type()

            cj = CookieJar()
            for row in rows:
                n = row[0]
                path = row[1]
                secure = row[2]
                val = row[3]
                #decrypt encrypted_value if no value entry
                if len(val)==0:
                    if platform.system() == 'Linux' or sys.platform=="darwin":
                        #http://stackoverflow.com/questions/23153159/decrypting-chromium-cookies/23727331#23727331
                        #https://n8henrie.com/2014/05/decrypt-chrome-cookies-with-python/
                        encrypted_value = bytes(row[4])

                        # Trim off the 'v10' that Chrome/ium prepends
                        encrypted_value = encrypted_value[3:]

                        # Default values used by both Chrome and Chromium in OSX and Linux
                        salt = b'saltysalt'
                        iv = b' ' * 16
                        length = 16

                        my_pass = my_pass.encode('utf8')

                        key = PBKDF2(my_pass, salt, length, iterations)
                        cipher = AES.new(key, AES.MODE_CBC, IV=iv)

                        decrypted = cipher.decrypt(encrypted_value)
                        #print("dec = "+decrypted)
                        val = clean(decrypted)

                #todo respect the path component of the cookies with respect to the request

                #respect the secure flag
                if req_type!="https" and secure!=True:
                        continue

                #build a cookie
                c = Cookie(version=0,
                                                name=n, value=val,
                                                port=port, port_specified=False,
                                                domain=domain, domain_specified=True, domain_initial_dot=False,
                                                path=path, path_specified=True, secure=secure,
                                                expires=None, discard=False,
                                                comment=None, comment_url=None,
                                                rest={})
                #ui.status("Found {} in Chrome\n".format(n))
                cj.set_cookie(c)

            return cj


def extsetup():
        global current_user
        ui = mercurial.ui.ui()

        def open_wrapper(func):
                def open(*args, **kwargs):
                        #TortoiseHG doesn't appear to have the necessary DLLs for sqlite3
                        #so assume they're in the same folder as this script
                        if platform.system() == 'Linux':
                            path = '/usr/lib'
                            sys.path.insert(0, path)
                        else:
                            script = inspect.stack()[0][1]
                            path = os.path.dirname(script)
                            sys.path.insert(0, path)

                        if isinstance(args[0], Request):
                                request = args[0]

                                r_url = request.get_full_url()

                                cj = CookieJar()
                                browsers = [Chrome]
                                for browser in browsers:
                                        objType = type(browser)
                                        browser_jar = browser().get_cookies(request, ui)

                                        for cookie in browser_jar:
                                                cj.set_cookie(cookie)

                                cj.add_cookie_header(request)
                                response = func(*args, **kwargs)

                                #if there has been a redirect, assume authentication cookies are invalid
                                #or out of date
                                if r_url != response.geturl():
                                        #produce the basic url without HG commands query strings
                                        url = urlparse.urljoin(r_url, urlparse.urlparse(r_url).path)

                                        ui.warn("Redirect, assuming authentication cookies out of date\n")
                                        #webbrowser.open_new(url)

                                        raise urllib2.HTTPError(request.get_full_url(), 401, "Authorisation failed, re-authenticate browser session", {}, None)
                        else:
                                response = func(*args, **kwargs)
                        return response
                return open

        old_opener = mercurial.url.opener
        def opener(*args, **kwargs):
                urlopener = old_opener(*args, **kwargs)
                urlopener.open = open_wrapper(urlopener.open)
                return urlopener
        mercurial.url.opener = opener

0 个答案:

没有答案