Giter Site home page Giter Site logo

Comments (25)

Sudrien avatar Sudrien commented on May 28, 2024 1

Confirmed @bigfootjon 's code works. Less monkey patch, more direct hacking...

my certbot.hover.sh is looking like

TOKEN=$(oathtool -b --totp 'MY_TOTP_SECRET')
PROVIDER_CREDENTIALS=("--auth-username=MY_USERNAME" "--auth-password=MY_PASSWORD" "--auth-token=${TOKEN}")

I think a pyotp integration might be appropriate? --auth-totp-secret instead of --auth-token

#539 #716 #771 #884 seem to be covered by this as well

from lexicon.

adferrand avatar adferrand commented on May 28, 2024 1

Hello @Sudrien, I fixed the issues that have been caught, you can test again.

from lexicon.

Emporioo avatar Emporioo commented on May 28, 2024

Same problem encountered here.

I thought toggling it off in account settings would do the trick but it just remains on, reading further into it I noticed they state it's now mandatory. Frustrating!

I've contacted Hover, if no change (which I highly doubt unfortunatly...) I'll change provider.

from lexicon.

Emporioo avatar Emporioo commented on May 28, 2024

Just to update... I moved my domain to Google and now using a service called ddclient.

Not sure what OPs use case is but for me I simply needed a way to update my domain to reference my external dynamic IP.

ddclient does the job beautifully and seems to be very popular and well maintained/documented.
I wish I had discovered it sooner. It took me a long time to get the (now broken) Hover script working in this way.

from lexicon.

bkanuka avatar bkanuka commented on May 28, 2024

Hey - I'm the original contributer of the Hover provider in lexicon. I got a nice surprise when my certbot and wildcard certificates failed!

I'm also going to contact Hover support, but I suspect this will also drive me to change providers 😞

from lexicon.

bkanuka avatar bkanuka commented on May 28, 2024

I contacted Hover support, and they were not immediately helpful. I switched to using Google Cloud for DNS becuause that's what I use in my day job. It costs me $0.01/day or $0.30/month so its almost free. I'm sure there are other free DNS providers to switch to.

from lexicon.

bigfootjon avatar bigfootjon commented on May 28, 2024

It is actually possible to login with 2fa using dns-lexicon

I've monkey-patched my local implementation to do this:

# The provided _authenticate function does not provide authentication
# for 2fa-enabled accounts. This shim does that
def _new_authenticate(self: hover.Provider) -> None:
    # Getting required cookies "hover_session" and "hoverauth"
    response = requests.get("https://www.hover.com/signin")
    self.cookies["hover_session"] = response.cookies["hover_session"]

    # Part one, login credentials
    payload = {
        "username": self._get_provider_option("auth_username"),
        "token": None,
        "password": self._get_provider_option("auth_password"),
    }
    response = requests.post(
        "https://www.hover.com/signin/auth.json", json=payload, cookies=self.cookies
    )
    response.raise_for_status()

    # Part two, 2fa
    payload = {
        "code": self._get_provider_option("auth_token"),
    }
    response = requests.post(
        "https://www.hover.com/signin/auth2.json", json=payload, cookies=self.cookies
    )
    response.raise_for_status()

    if "hoverauth" not in response.cookies:
        raise Exception("Unexpected auth response")
    self.cookies["hoverauth"] = response.cookies["hoverauth"]

    # Make sure domain exists
    # domain is stored in self.domain from BaseProvider

    domains = self._list_domains()
    for domain in domains:
        if domain["name"] == self.domain:
            self.domain_id = domain["id"]
            break
    else:
        raise AuthenticationError(f"Domain {self.domain} not found")


hover.Provider._authenticate = _new_authenticate

If this looks like a reasonable implementation I'd be happy to open a PR

from lexicon.

adferrand avatar adferrand commented on May 28, 2024

Ok guys, let's tackle this.

So basically it seems that we have two approaches:

  1. either exposing an OTP generated outside of Lexicon through a new flag like --auth-token
  2. or generate the OTP directly in Lexicon using a provided secret through a new flag like --auth-totp-secret and the integration of a Python OTP library.

The issues review from Sudrien seems to indicate that OTP could be used in other providers, in place of dedicated static application credentials. Also pyotp seems a very light library with no dependency and large Python compatibility and activate maintenance. I am usually reluctant to add a dependency either globally to avoid big dependency graphs, or for a specific provider given the added complexity to handle this user-side. But here it seems to be a reasonable move.

So I will create a PR for hover with the approach proposed by @bigfootjon + the flag and pyotp integration proposed by @Sudrien.

Then, since I have no active account for Hover, I would like that one of you test the updated provider and generate the new set of cassettes for the integration tests. Sounds good to you ?

from lexicon.

bigfootjon avatar bigfootjon commented on May 28, 2024

Unfortunately I’m traveling for the next few weeks so I’ll be unable to test until then, but the code looks conceptually correct to me

from lexicon.

Sudrien avatar Sudrien commented on May 28, 2024

Sorry, more of a rubygems person usually

pip install git+https://github.com/AnalogJ/lexicon.git@hover-otp

somthing worked

lexicon hover -h

New option shows

PROVIDER_CREDENTIALS=("--auth-username=MY_USERNAME" "--auth-password=MY_PASSWORD" "--auth-totp-secret=MY_TOTP_SECRET")

Note: MY_TOTP_SECRET should have no whitespace, according to quick pyotp test - what breaks when I have it in? Test this later

trying this with my test call for last night...

manual-auth-hook command "/root/certbot.hover.sh auth" returned error code 1
Error output from manual-auth-hook command certbot.hover.sh:
Traceback (most recent call last):
  File "/usr/local/bin/lexicon", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.9/dist-packages/lexicon/_private/cli.py", line 135, in main
    results = client.execute()
  File "/usr/local/lib/python3.9/dist-packages/lexicon/client.py", line 194, in execute
    executor = self.__enter__()
  File "/usr/local/lib/python3.9/dist-packages/lexicon/client.py", line 151, in __enter__
    raise e
  File "/usr/local/lib/python3.9/dist-packages/lexicon/client.py", line 143, in __enter__
    provider = self.provider_class(self.config)
TypeError: Can't instantiate abstract class Provider with abstract method authenticate

....

Which seems to be about

def _authenticate(self) -> None:

in hover.py but switching it back gets rid of the error with no actual dns change, and thus challenge failure.

from lexicon.

Sudrien avatar Sudrien commented on May 28, 2024

Wait, switched to

def authenticate(self):

from

def _authenticate(self) -> None:

and removed

"token": None,

in the first call from hover.py and I'm getting success.

Doing the MY_TOTP_SECRET with whitspace test mentioned above...

manual-cleanup-hook command "/root/certbot.hover.sh cleanup" returned error code 1
Error output from manual-cleanup-hook command certbot.hover.sh:
Traceback (most recent call last):
  File "/usr/local/bin/lexicon", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.9/dist-packages/lexicon/_private/cli.py", line 135, in main
    results = client.execute()
  File "/usr/local/lib/python3.9/dist-packages/lexicon/client.py", line 194, in execute
    executor = self.__enter__()
  File "/usr/local/lib/python3.9/dist-packages/lexicon/client.py", line 151, in __enter__
    raise e
  File "/usr/local/lib/python3.9/dist-packages/lexicon/client.py", line 144, in __enter__
    provider.authenticate()
  File "/usr/local/lib/python3.9/dist-packages/lexicon/_private/providers/hover.py", line 59, in authenticate
    payload = {"code": self.totp.now()}
  File "/usr/local/lib/python3.9/dist-packages/pyotp/totp.py", line 64, in now
    return self.generate_otp(self.timecode(datetime.datetime.now()))
  File "/usr/local/lib/python3.9/dist-packages/pyotp/otp.py", line 35, in generate_otp
    hasher = hmac.new(self.byte_secret(), self.int_to_bytestring(input), self.digest)
  File "/usr/local/lib/python3.9/dist-packages/pyotp/otp.py", line 52, in byte_secret
    return base64.b32decode(secret, casefold=True)
  File "/usr/lib/python3.9/base64.py", line 231, in b32decode
    raise binascii.Error('Non-base32 digit found') from None
binascii.Error: Non-base32 digit found

So I'd suggest stripping all whitespace when feeding it into pyotp - as whitespace is often introduced to make human handling easier.

from lexicon.

Sudrien avatar Sudrien commented on May 28, 2024

My tests are all working as expected now, thank you.

from lexicon.

adferrand avatar adferrand commented on May 28, 2024

Hello @Sudrien, are you willing to go ahead and update the cassettes stored in the repository for Hover provider, that allows offline integration tests? It is basically about:

If not, my alternative is that you provide me some temporary credentials and I do it directly.

from lexicon.

Sudrien avatar Sudrien commented on May 28, 2024

I can handle one dump, unfortunately what I'm seeing is a bit beyond my python knowledge at the moment.

@adferrand, Assuming your commit email is current, I've sent login information for my second account.

from lexicon.

bigfootjon avatar bigfootjon commented on May 28, 2024

Yeah I can confirm that this PR works for me

from lexicon.

simonevetere avatar simonevetere commented on May 28, 2024

hi, i install via pip install dns-lexicon how to update to have this modify ? like pip install will update the existing one with the fix for that ?

from lexicon.

simonevetere avatar simonevetere commented on May 28, 2024

It is actually possible to login with 2fa using dns-lexicon

I've monkey-patched my local implementation to do this:

# The provided _authenticate function does not provide authentication
# for 2fa-enabled accounts. This shim does that
def _new_authenticate(self: hover.Provider) -> None:
    # Getting required cookies "hover_session" and "hoverauth"
    response = requests.get("https://www.hover.com/signin")
    self.cookies["hover_session"] = response.cookies["hover_session"]

    # Part one, login credentials
    payload = {
        "username": self._get_provider_option("auth_username"),
        "token": None,
        "password": self._get_provider_option("auth_password"),
    }
    response = requests.post(
        "https://www.hover.com/signin/auth.json", json=payload, cookies=self.cookies
    )
    response.raise_for_status()

    # Part two, 2fa
    payload = {
        "code": self._get_provider_option("auth_token"),
    }
    response = requests.post(
        "https://www.hover.com/signin/auth2.json", json=payload, cookies=self.cookies
    )
    response.raise_for_status()

    if "hoverauth" not in response.cookies:
        raise Exception("Unexpected auth response")
    self.cookies["hoverauth"] = response.cookies["hoverauth"]

    # Make sure domain exists
    # domain is stored in self.domain from BaseProvider

    domains = self._list_domains()
    for domain in domains:
        if domain["name"] == self.domain:
            self.domain_id = domain["id"]
            break
    else:
        raise AuthenticationError(f"Domain {self.domain} not found")


hover.Provider._authenticate = _new_authenticate

If this looks like a reasonable implementation I'd be happy to open a PR

can i see all your code please ? i don't have "hover."

from lexicon.

bigfootjon avatar bigfootjon commented on May 28, 2024

Hover is just the provider provided by lexicon. Its import path has moved around over time.

I deleted this code since a new release was made with similar code

from lexicon.

simonevetere avatar simonevetere commented on May 28, 2024

Hover is just the provider provided by lexicon. Its import path has moved around over time.

I deleted this code since a new release was made with similar code

so why my [dns-lexicon] hover api isn't working ?

from flask import  jsonify
from lexicon.config import ConfigResolver
from lexicon.client import Client

def dohoverapi(nome,ip):
    
    lexicon_config = {
        "provider_name" : "hover", # lexicon shortname for provider, see providers directory for available proviers
        "action": "create", # create, list, update, delete
        "domain": "x", # domain name
        "name" : nome,
        "content" : ip,
        "type": "A", # specify a type for record filtering, case sensitive in some cases.
        "hover": {
            "auth_username": "y",
            "auth_password": "z"
        }
    }

    config = ConfigResolver()
    config.with_env().with_dict(dict_object=lexicon_config)
    client = Client(config)
    results = client.execute()


dohoverapi("test","x.y.z.k")

response : 401 Client Error: Unauthorized

from lexicon.

bigfootjon avatar bigfootjon commented on May 28, 2024

Please look at this PR: #1718

or this documentation: https://dns-lexicon.readthedocs.io/en/latest/configuration_reference.html#hover

you need to pass a new option

from lexicon.

simonevetere avatar simonevetere commented on May 28, 2024

Please look at this PR: #1718

or this documentation: https://dns-lexicon.readthedocs.io/en/latest/configuration_reference.html#hover

you need to pass a new option

thanks for quick reply :

  1. i don't have "auth_totp_secret" in my code i install via pip install maybe isn't officially relesed ?
  2. where i can take this param ?

from lexicon.

bigfootjon avatar bigfootjon commented on May 28, 2024
  1. Yes it is officially released, please refer to the release notes: https://github.com/AnalogJ/lexicon/releases/tag/v3.15.0
  2. Not sure I understand this question

from lexicon.

simonevetere avatar simonevetere commented on May 28, 2024

auth_totp_secret <- what i have to put here ?

from lexicon.

simonevetere avatar simonevetere commented on May 28, 2024

idk guys i have to do in a different way :
with auth_totp_secret => xyz=== 422 (Unprocessable Entity)
i do :

in hover.py :
in __init ()

        otp_uri = 'otpauth://totp/Hover:name?secret=secret&issuer=Hover'
        self.totp = pyotp.parse_uri( otp_uri )

in authenticate():

payload = {"code": self.totp.now()}

now it work but everytime hover.com send me a mail new access

from lexicon.

bigfootjon avatar bigfootjon commented on May 28, 2024

Your auth_totp_secret is the value of “secret=“ in your URL

from lexicon.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.