Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gitee的模拟登录考虑加吗? #114

Open
zeno-io opened this issue Aug 14, 2020 · 3 comments
Open

gitee的模拟登录考虑加吗? #114

zeno-io opened this issue Aug 14, 2020 · 3 comments

Comments

@zeno-io
Copy link

zeno-io commented Aug 14, 2020

No description provided.

@zeno-io
Copy link
Author

zeno-io commented Aug 14, 2020

import requests
import re
import base64

# pip uninstall pycrypto
# pip install pycryptodome
# pip install Crypto
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA

# python2 和 python3的兼容代码
try:
    # python2 中
    import cookielib
except:
    # python3 中
    import http.cookiejar as cookielib


class GiteeLogin(object):
    def __init__(self, username, password):
        # 初始化信息
        self.headers = {
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
            "Accept-Encoding": "gzip, deflate, br",
            "Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
            "Connection": "keep-alive",
            "Content-Type": "application/x-www-form-urlencoded",
            "Host": "gitee.com",
            "Origin": "https://gitee.com",
            "Referer": "https://gitee.com/login",
            'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36",
        }
        # session代表某一次连接
        self.session = requests.Session()
        self.profile_url = 'https://gitee.com/profile'
        self.post_url = 'https://gitee.com/login'
        self.token_url = 'https://gitee.com/login'
        self.encryptCsrfToken = None
        self.encryptSeparator = None
        self.publicKey = None
        self.username = username
        self.password = password
        self.token = None
        # 因为原始的session.cookies 没有save()方法,所以需要用到cookielib中的方法LWPCookieJar,这个类实例化的cookie对象,就可以直接调用save方法。
        self.session.cookies = cookielib.LWPCookieJar(filename="giteeCookie.txt")

    # 登录入口
    def tryLogin(self):
        # 第一步:尝试使用已有的cookie登录
        try:
            self.session.cookies.load()
        except:
            print(f"Failed to load cookie.")

        isLogin = self.isLoginStatus()
        print(f"isLogin = {isLogin}")
        if isLogin == False:
            return self.login()
        return True

    # 通过访问个人中心页面的返回状态码来判断是否为登录状态
    def isLoginStatus(self):
        # 下面有两个关键点
        # 第一个是header,如果不设置,会返回500的错误
        # 第二个是allow_redirects,如果不设置,session访问时,服务器返回302,
        # 然后session会自动重定向到登录页面,获取到登录页面之后,变成200的状态码
        # allow_redirects = False  就是不允许重定向
        resp = self.session.get(self.profile_url, headers=self.headers, allow_redirects=False)
        if resp.status_code != 200:
            # print(f"Login Status, StatusCode = {resp.status_code}")
            return False
        else:
            return True

    # 登录入口
    def login(self):
        ok = self.prepare()
        if ok == False:
            return False

        plainStringText = '' + self.encryptCsrfToken + self.encryptSeparator + self.password
        formatPublicKey = self.publicKey.replace('\\n', '\n')
        encryptPassword = self.encryptStringByRSA(formatPublicKey, plainStringText)
        # print( self.encryptCsrfToken )
        # print( self.encryptSeparator )
        # print( self.password )

        postData = {
            "encrypt_key": "password",
            "utf8": "✓",
            "authenticity_token": self.token,
            "redirect_to_url": "",
            "user[login]": self.username,
            "encrypt_data[user[password]]": encryptPassword,
            "user[remember_me]": "0"
        }
        # print(postData)
        resp = self.session.post(self.post_url, data=postData, headers=self.headers)
        if resp.status_code != 200:
            print(f"Login Fail, StatusCode = {resp.status_code}")
            return False
        # print(f"Text = {resp.text}")

        index = resp.text.index('action="/login"')
        if index >= 0:
            return False

        # 登录成功之后,将cookie保存在本地文件中
        self.session.cookies.save()
        return True

    def prepare(self):
        resp = self.session.get(self.token_url, headers=self.headers)
        if resp.status_code != 200:
            print(f"Prepare Fail, StatusCode = {resp.status_code}")
            return None
        ok = self.parseKey(resp.text)
        if ok == False:
            return False
        ok = self.parseToken(resp.text)
        if ok == False:
            return False
        return True

    # Get login token
    def getToken(self):
        if self.token == None:
            resp = self.session.get(self.token_url, headers=self.headers)
            if resp.status_code != 200:
                print(f"Get Token Fail, StatusCode = {resp.status_code}")
                return None
            self.parseToken(resp.text)
        return self.token

    # parse key
    def parseKey(self, text):
        match = re.search(r'meta content="(.*?)" name="csrf-token"', text)
        if not match:
            print('Get Encrypt Csrf Token Fail')
            return False
        else:
            self.encryptCsrfToken = match.group(1)
        match = re.search(r'"separator":"(.*?)"', text)
        if not match:
            print('Get Encrypt separator Fail')
            return False
        else:
            self.encryptSeparator = match.group(1)
        match = re.search(r'"password_key":"(.*?)"', text)
        if not match:
            print('Get Public Key Fail')
            return False
        else:
            self.publicKey = match.group(1)
        return True

    # parse token
    def parseToken(self, text):
        match = re.search(r'name="authenticity_token" type="hidden" value="(.*?)"', text)
        if not match:
            print('Get Csrf Token Fail')
            return False
        self.token = match.group(1)
        return True

    # RSA 加密
    def encryptStringByRSA(self, publicKey, plainStringText):
        rsa_key = RSA.import_key(publicKey)
        cipher = PKCS1_OAEP.new(rsa_key)
        x = cipher.encrypt(plainStringText.encode())
        return base64.b64encode(x).decode()
    
    
    def force_sync_project(self, postUrl):
        postData = {
            "user_sync_code": "",
            "password_sync_code": "",
            "sync_wiki": "false",
            "authenticity_token": self.getToken()
        }
        resp = self.session.post(postUrl, data=postData, headers=self.headers, allow_redirects=False)
        if resp.status_code != 200:
            print(f"Failed to Force Sync Project, StatusCode = {resp.status_code}")
            print(f"Text = {resp.text}")
        else:
            print(f"Successful to Force Sync Project")


if __name__ == "__main__":
    # 用户名,密码请修改
    username = "SvenAugustus@outlook.com"
    password = "XXX" 

    login = GiteeLogin(username, password)
    status = login.tryLogin()
    if status == True:
        login.force_sync_project("https://gitee.com/svenaugustus/dubbo/force_sync_project")
    else:
        print(f"Login Fail")

我自己写的python脚本,登录没成功 o(╯□╰)o

@Kr1s77
Copy link
Owner

Kr1s77 commented Aug 17, 2020

@SvenAugustus 可以尝试,不太确定哦。

@Kr1s77
Copy link
Owner

Kr1s77 commented Aug 17, 2020

@SvenAugustus 测试了一下

在你 post 登录前你可以尝试发送请求到 https://gitee.com/check_user_login 验证一下
如果再响应体中出现 {"result":1,"failed_count":2} 这种信息,那就是说要需要输入验证码了,这时候需要去请求验证码,然后在 login post data 中添加 captcha 参数,其中填写请求下来的验证码。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants