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

Invalid Signature while Authorization handshake with API #1

Closed
1 task done
halfstackpgr opened this issue Apr 9, 2024 · 2 comments · Fixed by #2
Closed
1 task done

Invalid Signature while Authorization handshake with API #1

halfstackpgr opened this issue Apr 9, 2024 · 2 comments · Fixed by #2
Assignees
Labels
bug Something isn't working

Comments

@halfstackpgr
Copy link
Owner

halfstackpgr commented Apr 9, 2024

Status:

  • Needs help.

Issue related to Authorization.

  • The issue is regarding the authorization process of the website through API.
  • Both the Methods contain these parameters:
    • enable_auth which is a bool
    • auth_key which is a string.
    • secret which is a string as well.
    • time which is an int representing time in unix format.
  • While we pass these parameters to the method constructor. The error for Invalid Signature is being returned from the API.

Code where the problem is:

In AsyncMethod:

    def _generate_authorisation(
        self,
        end_point_url: str,
        method_name: t.Literal[
            "blogEntry.comments",
            "blogEntry.view",
            "contest.hacks",
            "contest.list",
            "contest.ratingChanges",
            "contest.standings",
            "contest.status",
            "problemset.problems",
            "problemset.recentStatus",
            "recentActions",
            "user.blogEntries",
            "user.friends",
            "user.info",
            "user.ratedList",
            "user.rating",
            "user.status",
        ],
    ) -> str:
        if self._auth_enabled is True:
            if not self._time:
                self._time = int(time.time())
            randon_six_digit_num = random.randint(111111, 999999)
            head = end_point_url.removeprefix(
                f"https://codeforces.com/api/{method_name}?"
            )
            to_hash = f"{randon_six_digit_num}/{method_name}?apiKey={self._auth_key}&{head}&time={self._time}#{self._secret}"
            hashed_string = (hashlib.sha512(to_hash.encode("utf8"))).hexdigest()
            final_url = f"https://codeforces.com/api/{method_name}?{head}&apiKey={self._auth_key}&time={self._time}&apiSig={randon_six_digit_num}{hashed_string}"
            return final_url
        else:
            return end_point_url

In SyncMethod:

    def _generate_authorisation(
        self,
        end_point_url: str,
        method_name: t.Literal[
            "blogEntry.comments",
            "blogEntry.view",
            "contest.hacks",
            "contest.list",
            "contest.ratingChanges",
            "contest.standings",
            "contest.status",
            "problemset.problems",
            "problemset.recentStatus",
            "recentActions",
            "user.blogEntries",
            "user.friends",
            "user.info",
            "user.ratedList",
            "user.rating",
            "user.status",
        ],
    ) -> str:
        if self._auth_enabled is True:
            if not self._time:
                self._time = int(time.time())
            randon_six_digit_num = random.randint(111111, 999999)
            head = end_point_url.removeprefix(
                f"https://codeforces.com/api/{method_name}?"
            )
            to_hash = f"{randon_six_digit_num}/{method_name}?apiKey={self._auth_key}&{head}&time={self._time}#{self._secret}"
            hashed_string = (hashlib.sha512(to_hash.encode("utf8"))).hexdigest()
            final_url = f"https://codeforces.com/api/{method_name}?{head}&apiKey={self._auth_key}&time={self._time}&apiSig={randon_six_digit_num}{hashed_string}"
            return final_url
        else:
            return end_point_url

To reproduce the error:

Asynchronous usage:

import asyncio
import pycodeforces

async def main():
    api = pycodeforces.AsyncMethod(enable_auth=True, auth_key="YOUR_AUTH_KEY", secret="YOUR SECRET")
    users = await api.get_user_info(handles="DmitriyH;Fefer_Ivan")
    # use `;` to add multiple parameters.
    async for user in users:
        print(user.avatar)

asyncio.run(main())

Synchronous usage:

import pycodeforces

async def main():
    get = pycodeforces.SyncMethod(enable_auth=True, auth_key="YOUR_AUTH_KEY", secret="YOUR SECRET")
    users = get.get_user_info(handles="DmitriyH;Fefer_Ivan")
    # use `;` to add multiple parameters.
    for user in users:
        print(user.avatar)

Reference to authorization with API:

In: Documentation

Ref:

image

Guessed Problem:

Hashing of apiSig. Or the way apiSig is hashed.

@halfstackpgr halfstackpgr added the bug Something isn't working label Apr 9, 2024
@halfstackpgr halfstackpgr self-assigned this Apr 9, 2024
@halfstackpgr halfstackpgr pinned this issue Apr 11, 2024
@Vauth
Copy link

Vauth commented Apr 17, 2024

The Codeforces API may requires the params to be sorted in lexicographical order. Try.

head = "&".join(sorted(head.split("&")))

# ... ?{head}&apiKey= ...

@halfstackpgr
Copy link
Owner Author

The Codeforces API may requires the params to be sorted in lexicographical order. Try.

head = "&".join(sorted(head.split("&")))

# ... ?{head}&apiKey= ...

Thank you for the recommendation, but seems like it should be ; and not &.
PS: I've fixed the issue but thank you for the review.

@halfstackpgr halfstackpgr linked a pull request Apr 17, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants