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

Fix non spec conformant login oauth flow #24

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions github/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ def __init__(self, http: ClientSession, client_id: str, client_secret: str, toke
self.token = token
self._login_state = ""

def get_login_url(self, redirect_uri: Union[str, URL], scope: str = "user repo") -> URL:
self._login_state = "".join(random.choices(string.ascii_lowercase + string.digits, k=64))
def get_login_url(self, user_id: str, scope: str = "user repo") -> URL:
user_id = user_id + "%"
self._randomState = "".join(random.choices(string.ascii_lowercase + string.digits, k=64))
self._login_state = user_id+self._randomState
return self.login_url.with_query({
"client_id": self.client_id,
"redirect_uri": str(redirect_uri),
Expand Down
10 changes: 6 additions & 4 deletions github/client_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,20 +92,22 @@ async def login_callback(self, request: web.Request) -> web.Response:
f"{error_msg}\n\n"
f"More info at {error_uri}")
try:
user_id = UserID(request.query["user_id"])
user_id_raw, randomState = (request.query["state"]).split('%')
user_id = UserID(user_id_raw)
code = request.query["code"]
state = request.query["state"]

except KeyError as e:
return web.Response(status=400, text=f"Missing {e.args[0]} parameter")
client = self.get(user_id)
if not client:
return web.Response(status=401, text="Invalid state token")
return web.Response(status=401, text="Invalid state token because no client")
try:
await client.finish_login(code, state)
except ValueError:
return web.Response(status=401, text="Invalid state token")
return web.Response(status=401, text="Invalid state token because of ValueError")
except (KeyError, ClientError):
return web.Response(status=401, text="Failed to finish login")
return web.Response(status=401, text=f"Failed to finish login")
resp = await client.query("viewer { login }")
user = resp["viewer"]["login"]
self.put(user_id, client.token)
Expand Down
5 changes: 3 additions & 2 deletions github/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ async def github(self, evt: MessageEvent) -> None:
@command.argument("flags", required=False, pass_raw=True)
@authenticated(required=False)
async def login(self, evt: MessageEvent, flags: str, client: Optional[GitHubClient]) -> None:
redirect_url = (self.bot.webapp_url / "auth").with_query({"user_id": evt.sender})
flags = flags.lower()
scopes = ["user:user", "public_repo", "admin:repo_hook"]
if "--no-repo" in flags:
Expand All @@ -120,8 +119,10 @@ async def login(self, evt: MessageEvent, flags: str, client: Optional[GitHubClie
scopes.remove("admin:repo_hook")
if "--private" in flags:
scopes.append("repo")
# Pass user_id for state in Oauth
user_id = evt.sender
login_url = str(self.bot.clients.get(evt.sender, create=True).get_login_url(
redirect_uri=redirect_url, scope=" ".join(scopes)))
user_id=user_id, scope=" ".join(scopes)))
if client:
username = await client.query("viewer { login }", path="viewer.login")
await evt.reply(f"You're already logged in as @{username}, but you can "
Expand Down