-
Notifications
You must be signed in to change notification settings - Fork 129
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 for permanent authentication failure if initial call to loadAuthenticationKey fails #28
Conversation
…oadAuthenticationKey fails, remove tracking of pending auth tasks (await should ensure that)
@pokusew Any changes you'd like to see for this PR to be accepted? Let me know! |
Hi @foxxyz, Sorry for my late reply. I've been a bit busy recently. Thank you very much for your PR. 🙂 I really appreciate your contribution. 👍 I looked into it and I think you are right 👍 (although I don't have any Mifare Classic card to test it). The issue can really occur in the situation you described. But I don't think that removing the tracking of Promises in Suppose no keys are loaded yet (initial state) and you have this code, where you want to authenticate two blocks (4 and 5): const key = 'FFFFFFFFFFFF';
const keyType = KEY_TYPE_A;
await Promise.all([
reader.authenticate(4, keyType, key),
reader.authenticate(5, keyType, key),
]); The following actions will occur in this order:
When there was no Of course, it will only appear when there are more than one consecutive But I obviously forgot to deal with the situation you described. I think I even forgot to clear the resolved Promise from I think that the best solution would be to clear On line 428 (after try/catch block), the following code can be added to remove the resolved/rejected Promise from the // remove the loadAuthenticationKey Promise from pendingLoadAuthenticationKey
// as it is already resolved or rejected
delete this.pendingLoadAuthenticationKey[key]; That should resolve all the issues. Is everything clear? What do you think of that? I'll be grateful for any comments on it. Could you please test if this solution works? I'm looking forward to your reply. PS Don't forget to star ⭐️ my library, if you find it useful. 😃 Thanks. |
…ltaneous authentication of multiple blocks better
Hello @pokusew! Sorry for my very late reply to your very detailed explanation. I think I understand the use-case you put forth, and I've added an additional commit that will hopefully address and mitigate these concerns. In summary, the After the authentication completes, the pending process is cleared using a I've tested correct behavior via the example, using both single and multiple authentication blocks, but I would invite you to check it as well. Let me know if this addresses the outstanding issues, and if not, what I can improve! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @foxxyz,
Thank you very much for your changes. I really appreciate it.
Unfortunately, I don't have any Mifare Classic cards, so I can't test it now (I have currently just Mifare Ultralight and Mifare DESFire – Yeah, I have to broaden my cards collection 😄).
I reviewed your code and everything looks fine – except the one possible situation that may occur.
Can you please take a look at it? (see my review comments)
Otherwise, I think that it solves the outstanding issues. 👍
Looking forward to your reply.
src/Reader.js
Outdated
|
||
} | ||
|
||
try { | ||
await this.pendingLoadAuthenticationKey[key]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suppose the following situation:
- key is not in the storage (condition
!keyNumber
is met) - there is already an authentication process for this key (so the condition
!this.pendingLoadAuthenticationKey[key]
is not met) - then try-catch-finally block is executed
- the
keyNumber
remainsnull
– that's the problem
You should assign return value ofawait this.pendingLoadAuthenticationKey[key]
tokeyNumber
(like in my code here on line 402). - when the command is constructed,
null
results in0x00
(which is the same as for0
), so it will work for one key, but the error could appear when using two keys – that's probably the reason why you didn't notice when you were testing it
Suggested fix: replace line 421 with the following code:
keyNumber = await this.pendingLoadAuthenticationKey[key];
P.S.: Yeah, in some cases, we know the keyNumber, but because of simplified conditions (much cleaner code), we need to reassign the keyNumber in order to handle the situation described above.
src/Reader.js
Outdated
} catch (err) { | ||
throw new AuthenticationError('unable_to_load_key', 'Could not load authentication key into reader.', err); | ||
} | ||
finally { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using finally is great solution! 👍 Thank you very much. I didn't realize that my previously suggested fix won't work.
Thank you @pokusew for the thorough review! The fix you suggested is indeed something I overlooked. Glad you found it! I have made the change, let me know if you see any other obstacles for merging! |
@pokusew Is the change sufficient for the PR to be accepted? Please let me know! |
Thank you for merging and for your great library! Keep up the good work! 👍 |
Hi @foxxyz, You are welcome! I greatly appreciate your contribution. 👍 It really makes a difference! Hope you enjoy using this library! Feel free to create another PR or an issue or to contact me if you encounter any problems or have a feature idea. P.S.: Check out the contributors field in package.json. 😉 BTW Sorry for my very late reply. I was a bit busy over the last few months. 🙂 I reviewed your last commit and accepted ✅ the changes. Moreover, I got a Mifare Classic card, so I was able to test the fix and it seems to work! 🙂 I merged the PR in f7c2ebf and released it in version 0.6.2. 🚀 |
When using authentication, it seems like a condition can occur that is impossible to recover from. It can be reproduced as follows:
examples/index.js
(lines 70-86, except for line 78)npm run example
error when authenticating data
When inspecting the code, this seems originate from Line 423 in Reader.js where the Promise of
load AuthenticationKey
is being stored inthis.pendingLoadAuthenticationKey
- presumably to be able to wait for this Promise to resolve at a later time.However, if this Promise is rejected (for example, a failed auth operation in
loadAuthenticationKey
), the rejected promise will now be stored inthis.pendingLoadAuthenticationKey
. Later calls toauthenticate
will now continue toawait
on this rejected Promise and never complete.This pull request removes the tracking of Promises in
this.pendingLoadAuthenticationKey
so subsequent calls toauthenticate
will now run the whole authentication key load procedure if the key is not present, no matter the result of the initial call. I believeawait
should ensure it will always run to completion anyway (except in case of an exception, of course).I want to make sure I'm not regressing any existing use-cases, so let me know if I'm missing your original intent when using
pendingLoadAuthenticationKey
or overlooking any situations dictating its need.