From bfae04723bd3155801f079ab5238018ec8a0cb09 Mon Sep 17 00:00:00 2001 From: Simeon Simeonov Date: Fri, 1 May 2026 14:34:04 +0200 Subject: Redesign API by introducing otp2289.OTPResponse type --- README.md | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index 38fa9a7..ef100aa 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ It requires no additional libraries. The main reason for writing this library was the need to login into my FreeBSD servers using [opiepasswd](https://en.wikipedia.org/wiki/OPIE_Authentication_System). -*opiepasswd* has since been removed from FreeBSD since version 14. +*opiepasswd* has meanwhile been removed from FreeBSD ( >=14). I decided to license the library under the [Simplified BSD License / 2-clause BSD license](https://codeberg.org/sgs/pyotp2289/src/branch/master/LICENSE) and not under the @@ -120,17 +120,16 @@ RFC-2289 consists of interactions between them. # initialization digest (hash). The password 'This is a test.' will give you # the same results as in the following example. passwd_bytes = getpass.getpass().encode() # Fetch the password as bytes - generator = otp2289.generator.OTPGenerator(passwd_bytes, - 'TesT', - otp2289.OTP_ALGO_MD5) - digest = generator.generate_otp_hexdigest(500) + generator = otp2289.OTPGenerator(passwd_bytes, 'TesT', otp2289.OTP_ALGO_MD5) + response = generator.generate_otp_response(500) # otp2289.OTPResponse + digest = response.hexdigest # digest is now: 0x2b8d82b6ac14346c # the client sends it to the server # the server creates the first state. Note that step is decremented by 1: - state = otp2289.server.OTPState(digest, 499, 'TesT', otp2289.OTP_ALGO_MD5) + state = otp2289.OTPState(digest, 499, 'TesT', otp2289.OTP_ALGO_MD5) # the state can be stored in a OTPStore container: - store = otp2289.server.OTPStore() + store = otp2289.OTPStore() # key can be any str that can be used to reference the state (f.i username) store.add_state('myusername', state) # where key can be any str that can be # OTPStore is provided only for convenience as it is not part of RFC-2289. @@ -145,12 +144,16 @@ RFC-2289 consists of interactions between them. # created earlier. RFC-2289 defines two types of responses: # - hex (like '0x2b8d82b6ac14346c') - more suited for automation # - tokens consisting of 6 short words - better when responding manually - hex_response = generator.generate_otp_hexdigest(499) # '0x6323f96296a2526b' - token_response = generator.generate_otp_words(499) + # + # OTPResponse object can represent a response in both formats: + response = generator.generate_otp_response(499) + hex_response = response.hexdigest # '0x6323f96296a2526b' + token_response = response.words # token_response is now: 'CANT JAW BITS NU LO PUP' # a possible shortcut may be to use the challenge-string directly: - hex_response = generator.generate_otp_hexdigest_from_challenge(challenge) - token_response = generator.generate_otp_words_from_challenge(challenge) + response = generator.generate_otp_response_from_challenge(challenge) + hex_response = response.hexdigest + token_response = response.words # ... giving the same results. # once the response is received, the server validates it by yet again using @@ -158,9 +161,11 @@ RFC-2289 consists of interactions between them. result = state.response_validates(hex_response) # or result = state.response_validates(token_response) + # or using the OTPResponse object directly + result = state.response_validates(response) # result should be True if the response matches the state, False if not # in case of invalid response or response checksum doesn't match, a - # otp2289.server.OTPInvalidResponse exception is raised. + # otp2289.OTPInvalidResponse exception is raised. # once the state has successfully validated the corresponding response, # the state **must never be used again** and a state corresponding to the @@ -170,7 +175,7 @@ RFC-2289 consists of interactions between them. # the next authentication attempt... challenge = state.challenge_string # challenge is now 'otp-md5 498 TesT ' # ... and on the client side... - hex_response = generator.generate_otp_hexdigest_from_challenge(challenge) + response = generator.generate_otp_response_from_challenge(challenge) # etc. etc... ``` -- cgit v1.3