40cc9430e0ac98faf2892e8e63a30a0a151827d9 — Matthias Gabriel 3 years ago 7a0f157
Add a GitLab provider for gitlab.com
2 files changed, 89 insertions(+), 0 deletions(-)

M passrotate/providers/__init__.py
A passrotate/providers/gitlab.py
M passrotate/providers/__init__.py => passrotate/providers/__init__.py +1 -0
@@ 12,3 12,4 @@ from passrotate.providers.facebook import Facebook
from passrotate.providers.zotero import Zotero
from passrotate.providers.pypi import PyPI
from passrotate.providers.ankiweb import AnkiWeb
from passrotate.providers.gitlab import GitLab
\ No newline at end of file

A passrotate/providers/gitlab.py => passrotate/providers/gitlab.py +88 -0
@@ 0,0 1,88 @@
import json

from passrotate.provider import Provider, ProviderOption, PromptType, register_provider
from passrotate.forms import get_form
from urllib.parse import urlparse
import requests
from bs4 import BeautifulSoup

class GitLab(Provider):
    username=Your GitLab username
    name = "GitLab"
    domains = [
    options = {
        "username": ProviderOption(str, "Your GitLab username")

    def __init__(self, options):
        self.username = options["username"]

    def _read_userid(self):
            r = self._session.get("https://gitlab.com/api/v4/user")
            self.user_id = json.loads(r.text)["id"]
            raise Exception("Can't read user id from API")

    def _handle_two_factor_auth(self, r):
        soup = BeautifulSoup(r.text, "html5lib")

        # look for the OTP input field
        otp_input = soup.find("input", attrs={ 'id': 'user_otp_attempt' })

        # if we didn't find it its probably not enabled, great!
        if otp_input is None:

        # else we ask the user to provide its token and send it
        code = self.prompt("Enter your two factor (TOTP) code", PromptType.totp)
        form = get_form(r.text)
            "user[otp_attempt]": code
        r = self._session.post("https://gitlab.com/users/sign_in", data=form)
        if r.status_code != 200:
            raise Exception("Unable to login via OTP")

    def _login(self, old_password):
        r = self._session.get("https://gitlab.com/users/sign_in")
        form = get_form(r.text)
            "user[login]": self.username,
            "user[password]": old_password
        r = self._session.post("https://gitlab.com/users/sign_in", data=form)
        if r.status_code != 200:
            raise Exception("Unable to log into GitLab account with current password")

        return r

    def _set_form(self):
        r = self._session.get("https://gitlab.com/profile/password/edit")
        self._form = get_form(r.text, id="edit_user_{}".format(self.user_id))

    def prepare(self, old_password):
        self._session = requests.Session()

        r = self._login(old_password)

    def execute(self, old_password, new_password):
            "user[current_password]": old_password,
            "user[password]": new_password,
            "user[password_confirmation]": new_password,
        r = self._session.post("https://gitlab.com/profile/password", data=self._form)