Skip to content

Commit 4f28b3f

Browse files
committed
pygit2: support interactive kb auth for http
1 parent ca14fee commit 4f28b3f

File tree

1 file changed

+37
-7
lines changed

1 file changed

+37
-7
lines changed

src/scmrepo/git/backend/pygit2/callbacks.py

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import os
12
from contextlib import AbstractContextManager
2-
from typing import TYPE_CHECKING, Callable, Optional, Union
3+
from types import TracebackType
4+
from typing import TYPE_CHECKING, Callable, Optional, Type, Union
35

46
from pygit2 import RemoteCallbacks as _RemoteCallbacks
57

@@ -20,14 +22,21 @@ def __init__(
2022
self,
2123
*args,
2224
progress: Optional[Callable[["GitProgressEvent"], None]] = None,
23-
**kwargs
25+
**kwargs,
2426
):
2527
super().__init__(*args, **kwargs)
2628
self.progress = GitProgressReporter(progress) if progress else None
2729
self._store_credentials: Optional["Credential"] = None
30+
self._tried_credentials = False
2831

29-
def __exit__(self, *args, **kwargs):
30-
self._approve_credentials()
32+
def __exit__(
33+
self,
34+
exc_type: Optional[Type[BaseException]],
35+
exc_value: Optional[BaseException],
36+
traceback: Optional[TracebackType],
37+
):
38+
if exc_type is None:
39+
self._approve_credentials()
3140

3241
def sideband_progress(self, string: str):
3342
if self.progress is not None:
@@ -36,16 +45,37 @@ def sideband_progress(self, string: str):
3645
def credentials(
3746
self, url: str, username_from_url: Optional[str], allowed_types: int
3847
) -> "_Pygit2Credential":
39-
from pygit2 import Passthrough
48+
from getpass import getpass
49+
50+
from pygit2 import GitError, Passthrough
4051
from pygit2.credentials import GIT_CREDENTIAL_USERPASS_PLAINTEXT, UserPass
4152

53+
if self._tried_credentials:
54+
raise GitError(f"authentication failed for '{url}'")
55+
self._tried_credentials = True
56+
4257
if allowed_types & GIT_CREDENTIAL_USERPASS_PLAINTEXT:
4358
try:
44-
creds = Credential(username=username_from_url, url=url).fill()
45-
self._store_credentials = creds
59+
if self._store_credentials:
60+
creds = self._store_credentials
61+
else:
62+
Credential(username=username_from_url, url=url).fill()
63+
self._store_credentials = creds
4664
return UserPass(creds.username, creds.password)
4765
except CredentialNotFoundError:
4866
pass
67+
68+
if os.environ.get("GIT_TERMINAL_PROMPT") != "0":
69+
try:
70+
if username_from_url:
71+
username = username_from_url
72+
else:
73+
username = input(f"Username for '{url}': ")
74+
password = getpass(f"Password for '{url}': ")
75+
if username and password:
76+
return UserPass(username, password)
77+
except KeyboardInterrupt:
78+
pass
4979
raise Passthrough
5080

5181
def _approve_credentials(self):

0 commit comments

Comments
 (0)