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

TOTP Token Issue with Multiple Logins #188

Open
PetarMilinovic opened this issue Dec 3, 2024 · 1 comment
Open

TOTP Token Issue with Multiple Logins #188

PetarMilinovic opened this issue Dec 3, 2024 · 1 comment

Comments

@PetarMilinovic
Copy link

PetarMilinovic commented Dec 3, 2024

I might be misunderstanding how this code works, but I’m running into an issue when pulling data from a NAS system with TOTP enabled. Specifically, I can log in to one system (like Core), but when I try logging into another system (like Active Backup for Business), the login fails.

It seems like the TOTP token gets invalidated immediately after the first use. So, when the second system tries to log in, it can’t because the token is no longer valid. I know this is Synology sided because they disable the Token but i didnt find a way to open a session so i could just log in once and add the session as a parameter or sth.

Here’s a quick code snippet to illustrate what’s happening:

   sys_info = core_sys_info.SysInfo(
            ip_address=ip_address,
            port=port,
            username=username,
            password=password,
            secure=True,
            cert_verify=False,
            dsm_version=7,
            debug=False,
            otp_code=otp_token,  # Generated Token
        )  # Passing session here
      
        # this login wont work because the totp token is already used
        active_backup = core_active_backup.ActiveBackupBusiness(
            ip_address=ip_address,
            port=port,
            username=username,
            password=password,
            secure=True,
            cert_verify=False,
            dsm_version=7,
            debug=False,
            otp_code=otp_token,  # Generated Token
        )

I have a potential fix for this, but I’m not entirely sure if it’s secure or well-written, since I’m not very familiar with Python. If anyone could review it, I’d really appreciate it. I just want to make sure I’m not introducing any security issues or bad practices with the solution:

from typing import Optional, Any
from . import auth as syn


class BaseApi(object):
    # Class-level attribute to store the shared session
    shared_session: Optional[syn.Authentication] = None

    def __init__(self,
                 ip_address: Optional[str] = None,
                 port: Optional[str] = None,
                 username: Optional[str] = None,
                 password: Optional[str] = None,
                 secure: bool = False,
                 cert_verify: bool = False,
                 dsm_version: int = 7,
                 debug: bool = True,
                 otp_code: Optional[str] = None,
                 application: str = 'Core',
                 ) -> None:

        self.application = application

        # Reuse shared session if it exists, otherwise create a new one
        if BaseApi.shared_session:
            self.session = BaseApi.shared_session
        else:
            if not all([ip_address, port, username, password]):
                raise ValueError("Missing required credentials for initial authentication.")

            self.session = syn.Authentication(
                ip_address, port, username, password, secure, cert_verify, dsm_version, debug, otp_code
            )
            self.session.login(self.application)
            self.session.get_api_list(self.application)
            self.session.get_api_list()

            # Store the new session in the shared class-level attribute
            BaseApi.shared_session = self.session

        # Initialize other attributes from the session
        self.request_data: Any = self.session.request_data
        self.batch_request = self.session.request_multi_datas
        self.core_list: Any = self.session.app_api_list
        self.gen_list: Any = self.session.full_api_list
        self._sid: str = self.session.sid
        self.base_url: str = self.session.base_url

    def logout(self) -> None:
        """Logs out and clears the shared session."""
        if self.session:
            self.session.logout(self.application)
            if BaseApi.shared_session == self.session:
                BaseApi.shared_session = None
        return

Thanks so much for looking into this!

@N4S4
Copy link
Owner

N4S4 commented Dec 4, 2024

Hello, thanks for reporting and yes atm the repo makes use of one otp at the time. So for multiple use you should use a different otp which is odd and i honestly do not use the option myself. However i will look into your code and let you know if it is good, than maybe you can make a PR? Give me sometimes as im far from home

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