-
Notifications
You must be signed in to change notification settings - Fork 16
feat: Noports CLI implementation #2304
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
base: trunk
Are you sure you want to change the base?
Conversation
| StringBuffer cbuf = StringBuffer(); | ||
| cbuf.append(NPIssueKeys.baseEnrollCommand | ||
| .replaceFirst('<atsign>', params.atsign) | ||
| .replaceFirst('<otp>', params.otp!)); |
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.
baseEnrollCommand is <atsign>:enroll:otp:<otp>; replace placeholders with actual values
| .fetchEnrollmentRequests(enrollmentListParams: enrollListParams); | ||
|
|
||
| if (enrollRequests.isEmpty) { | ||
| // keeps the loop active until enrollment fetched or terminated |
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.
Currently keeps retrying forever until successful or terminated. Should we consider having a retry limit?
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.
Nope; but we should consider having a resume if the user accidentally terminated before successful
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.
The resume mechanism has been added through the latest commits. The mechanism works by serializing the NPActivateParams and then reading when available.
|
Changes in the last batch of commits:
|
| final String? keysFilePath; | ||
|
|
||
| if (_params.atKeysFilePath == null) { | ||
| // Use the default path from onboarding service preferences |
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.
Workaround to avoid conflicts with creating atKeys files. Currently fetches the defaultPath from OnboardingServiceImpl.
Changes required: OnboardingService should throw a dedicated exception for key file name collisions, which can then be caught and handled.
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.
Need to address this issue fully in this PR. Find the places that MUST have file existence checking (onboard, enroll), ensure the checking always happens there. Remove file existence checking from elsewhere and verify that all the ways we create atKeys files do end up having a file existence check so we don't ever overwrite keys files. As a final safeguard, put a check into the place we finally write an AtKeys file and do not permit overwriting.
| /// Returns: 0 on success, 1 on failure | ||
| Future<int> wrappedMain() async { | ||
| await _initAtClient(); | ||
|
|
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.
If existing matching enrolment present, approves it
XavierChanth
left a comment
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.
Minor changes and some questions.
| ); | ||
| } | ||
|
|
||
| final activationString = results.rest.first; |
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.
Why .first instead of .single?
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.
.first keeps the cli lenient by avoiding errors when extra values are passed. But .single seems clearer and more straighforward, so I've replaced .first with .single through 90a00f6
packages/dart/noports_core/lib/src/commands/activate/activate_params.dart
Show resolved
Hide resolved
| final logger = AtSignLogger('Activate', loggingHandler: CLILoggingHandler()) | ||
| ..level = 'info'; | ||
|
|
||
| Activate._(this._onboardingService, this._params); |
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.
Nit: the strongly constructor shouldn't be private, most non-binary consumers of this api will prefer this over the factory constructor.
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.
Constructor made public through 90a00f6
| loggingHandler: CLILoggingHandler(), | ||
| )..level = 'info'; | ||
|
|
||
| IssueKeys._(this._params); |
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.
Same here.
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.
Constructor made public through 90a00f6
|
|
||
| // Enrollment: <atsign>:enroll:otp:<otp>[:name:<device>:keyfile:<path>] | ||
| static final enroll = RegExp( | ||
| r'^(?<atsign>[^:]+):enroll:otp:(?<otp>[A-Za-z0-9]{6})' |
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.
This is ordered, which is fine simple is best. Just make sure the Desktop app respects the same order when it gets implemented there.
Ideally the app consumes the same classes.
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.
This was left behind. The keys file is not accepted through the activation_string anymore; it can be passed as a separate arg with -k (or) -key-file. I'll make sure the desktop app works as expected.
| ${chalk.bold('Usage:')} noports activate ${chalk.cyan('<activation_string>')} [options] | ||
| ${chalk.bold('Options:')} | ||
| -k, --keyfile <path> Path to save atKeys file |
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.
Looks like the help wasn't updated
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.
I did update it earlier, I also reworked them again through (8a4a9d7).
| return chalk.red('ERR'); | ||
| case Level.INFO: | ||
| default: | ||
| return chalk.blueBright('INFO'); |
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.
Why not upstream this to atlogger hidden behind a boolean switch?
| @@ -0,0 +1,3 @@ | |||
| class HelpRequestedException implements Exception{ | |||
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.
Your Pr needs formatting
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.
addressed in my last commit
|
Feedback:
So there's 3 functions to the NoPorts CLI that I'm aware of
Right now 1 and 3 are in the same |
Then it no longer solves the original goal. The original goal is to create a string format that encodes all of the information required to transmit an atSign between machines for use with NoPorts. As soon as you separate the commands, or add options and flags, you have now coupled the use-case to the CLI and it is no longer compatible with the desktop app. |
Makes sense, It was just some feedback I had during my 30min call with Srie. If there was an original vision that I wasn't aware of, then we can ignore my suggestion |
This is covered in my onboarding document. |
| } | ||
|
|
||
| logger.shout('KeysFile exists at $keysFilePath'); | ||
| _params.atKeysFilePath = promptUser( |
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.
what happens if the user puts the same path in again?
| final String? keysFilePath; | ||
|
|
||
| if (_params.atKeysFilePath == null) { | ||
| // Use the default path from onboarding service preferences |
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.
Need to address this issue fully in this PR. Find the places that MUST have file existence checking (onboard, enroll), ensure the checking always happens there. Remove file existence checking from elsewhere and verify that all the ways we create atKeys files do end up having a file existence check so we don't ever overwrite keys files. As a final safeguard, put a check into the place we finally write an AtKeys file and do not permit overwriting.
| ); | ||
| } | ||
|
|
||
| static String? _parseAtsign(String input, ActivateType type) { |
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.
Return type should be Atsign? not String?
| return match?.namedGroup(ActivateRegexGroups.deviceName); | ||
| } | ||
|
|
||
| Map<String, String?> toJson() { |
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.
Why is type not part of the json?
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.
You are missing a test somewhere to ensure this kind of problem doesn't happen
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.
after further discussion we concluded that toJson is no longer needed and can be removed from this class
| if (existingEnrollment != null) { | ||
| await _approveEnrollment(existingEnrollment); | ||
| return 0; | ||
| } |
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.
personal preference, I would prefer the rest of this code were in an else block
|
|
||
| if (results.isNotEmpty) { | ||
| logger.info('Enrollment found with id: ${results.first.enrollmentId}'); | ||
| return results.first; |
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.
Should we be asserting there be just one? Or at least an explanation that we can only expect at most one result.
| return chalk.red('ERR'); | ||
| case Level.INFO: | ||
| default: | ||
| return chalk.blueBright('INFO'); |
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.
OK
| displayBanner(); | ||
| AtSignLogger.root_level = 'severe'; | ||
| return AtSignLogger('NoPorts', loggingHandler: CLILoggingHandler()) | ||
| ..level = 'info'; |
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.
No way for the user to change the log level?
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.
add --verbose | -v and --debug as we have for sshnpd
Closes #1976
- What I did
activateandissue-keyscommandsissue-keysgenerates copy-pasteable activation strings,activateaccepts them.- How I did it
Core Architecture:
Activate Command:
Issue-Keys Command:
IssueKeysParamsthat has it's arg parser impl and parsing- How to verify it
sshnoports/to generate binariesnoports issue-keys <@atsign>to generate an enrollment stringnoports activate <string>to activate- Description for the changelog
feat: introduce noports CLI with support for commands: 'activate' and 'issue-keys'