1
1
using System ;
2
2
using System . Collections . Generic ;
3
+ using System . Diagnostics ;
3
4
using System . Globalization ;
4
5
using System . IO ;
5
6
using System . Linq ;
7
+ using System . Reflection ;
8
+ using System . Runtime . Serialization ;
6
9
using System . Text ;
7
10
using System . Text . RegularExpressions ;
8
11
using System . Threading . Tasks ;
@@ -198,6 +201,13 @@ public ConnectedContext(AuthCommon auth)
198
201
Description = "Change the sharing permissions of an individual record" ,
199
202
Action = ShareRecordCommand
200
203
} ) ;
204
+ Commands . Add ( "import" ,
205
+ new ParseableCommand < ImportCommandOptions >
206
+ {
207
+ Order = 33 ,
208
+ Description = "Imports records from JSON file" ,
209
+ Action = ImportCommand
210
+ } ) ;
201
211
202
212
if ( auth . AuthContext . Enforcements . TryGetValue ( "allow_secrets_manager" , out var value ) )
203
213
{
@@ -995,16 +1005,7 @@ private void AssignRecordFields(KeeperRecord record, CmdLineRecordField[] fields
995
1005
{
996
1006
if ( typedField . GetValueAt ( idx ) is IFieldTypeSerialize typedValue )
997
1007
{
998
- foreach ( var pair in field . Value . Split ( ',' ) )
999
- {
1000
- var pos = pair . IndexOf ( '=' ) ;
1001
- var element = pos > 0 ? pair . Substring ( 0 , pos ) : pair ;
1002
- var value = pos > 0 ? pair . Substring ( pos + 1 ) : "" ;
1003
- if ( ! typedValue . SetElementValue ( element , value ) )
1004
- {
1005
- throw new Exception ( $ "Field type { field . FieldName } : Invalid element name: { element } .") ;
1006
- }
1007
- }
1008
+ typedValue . SetValueAsString ( field . Value ) ;
1008
1009
}
1009
1010
else
1010
1011
{
@@ -1037,7 +1038,7 @@ private void VerifyTypedFields(CmdLineRecordField[] fields, RecordType recordTyp
1037
1038
{
1038
1039
field . FieldLabel = rtf . FieldLabel ;
1039
1040
field . IsRecordField = true ;
1040
- if ( rtf . RecordField . Multiple == RecordFieldMultiple . Default )
1041
+ if ( rtf . RecordField . Multiple == RecordFieldMultiple . Always )
1041
1042
{
1042
1043
recordFields . Remove ( field . FieldName ) ;
1043
1044
}
@@ -1057,7 +1058,7 @@ private void VerifyTypedFields(CmdLineRecordField[] fields, RecordType recordTyp
1057
1058
1058
1059
if ( string . IsNullOrEmpty ( field . FieldIndex ) ) continue ;
1059
1060
1060
- if ( recordField . Multiple != RecordFieldMultiple . Default )
1061
+ if ( recordField . Multiple != RecordFieldMultiple . Always )
1061
1062
{
1062
1063
throw new Exception ( $ "Record field \" { field . FieldName } \" does not support multiple values") ;
1063
1064
}
@@ -1956,7 +1957,7 @@ record = folder.Records.Select(x => _vault.GetRecord(x)).FirstOrDefault(x =>
1956
1957
var clientKey = t . Item2 ;
1957
1958
1958
1959
Console . WriteLine ( "Successfully generated Client Device\n " ) ;
1959
- Console . WriteLine ( $ "One-Time Access Token: { clientKey } ") ;
1960
+ Console . WriteLine ( $ "One-Time Access Token: { clientKey } ") ;
1960
1961
var ipLock = device . LockIp ? "Enabled" : "Disabled" ;
1961
1962
Console . WriteLine ( $ "IP Lock: { ipLock } ") ;
1962
1963
var firstAccessOn = device . FirstAccessExpireOn . HasValue ? device . FirstAccessExpireOn . Value . ToString ( "G" ) : "Taken" ;
@@ -1966,7 +1967,7 @@ record = folder.Records.Select(x => _vault.GetRecord(x)).FirstOrDefault(x =>
1966
1967
}
1967
1968
else if ( action == "delete-client" )
1968
1969
{
1969
- if ( string . IsNullOrEmpty ( arguments . ClientName ) )
1970
+ if ( string . IsNullOrEmpty ( arguments . ClientName ) )
1970
1971
{
1971
1972
Console . Write ( "\" client-name\" parameter is required" ) ;
1972
1973
return ;
@@ -2461,6 +2462,53 @@ record = r;
2461
2462
}
2462
2463
}
2463
2464
2465
+ private async Task ImportCommand ( ImportCommandOptions options )
2466
+ {
2467
+ void Logger ( Severity severity , string message )
2468
+ {
2469
+ if ( severity == Severity . Warning || severity == Severity . Error )
2470
+ {
2471
+ Console . WriteLine ( message ) ;
2472
+ }
2473
+ Debug . WriteLine ( message ) ;
2474
+ }
2475
+
2476
+ if ( ! File . Exists ( options . FileName ) )
2477
+ {
2478
+ throw new Exception ( $ "File \" { options . FileName } \" does not exist") ;
2479
+ }
2480
+ var json = File . ReadAllText ( options . FileName ) ;
2481
+ var j_options = new ZeroDep . JsonOptions {
2482
+ DateTimeStyles = DateTimeStyles . None ,
2483
+ } ;
2484
+ j_options . SerializationOptions &= ~ ZeroDep . JsonSerializationOptions . AutoParseDateTime ;
2485
+ var j = ZeroDep . Json . Deserialize < Dictionary < string , object > > ( json , j_options ) ;
2486
+ var import = KeeperImport . LoadJsonDictionary ( j ) ;
2487
+ var result = await _vault . ImportJson ( import , Logger ) ;
2488
+ var table = new Tabulate ( 2 )
2489
+ {
2490
+ LeftPadding = 4
2491
+ } ;
2492
+ table . SetColumnRightAlign ( 0 , true ) ;
2493
+ if ( result . SharedFolderCount > 0 )
2494
+ {
2495
+ table . AddRow ( "Shared Folders:" , result . SharedFolderCount ) ;
2496
+ }
2497
+ if ( result . FolderCount > 0 )
2498
+ {
2499
+ table . AddRow ( "Folders:" , result . FolderCount ) ;
2500
+ }
2501
+ if ( result . TypedRecordCount > 0 )
2502
+ {
2503
+ table . AddRow ( "Records:" , result . TypedRecordCount ) ;
2504
+ }
2505
+ if ( result . LegacyRecordCount > 0 )
2506
+ {
2507
+ table . AddRow ( "Legacy Records:" , result . LegacyRecordCount ) ;
2508
+ }
2509
+ table . Dump ( ) ;
2510
+ }
2511
+
2464
2512
private Task RecordTypeInfoCommand ( RecordTypeInfoOptions options )
2465
2513
{
2466
2514
Tabulate table = null ;
@@ -2475,7 +2523,7 @@ private Task RecordTypeInfoCommand(RecordTypeInfoOptions options)
2475
2523
table . AddRow ( f . Name , f . Type ? . Name ,
2476
2524
f . Multiple == RecordFieldMultiple . Optional
2477
2525
? "optional"
2478
- : ( f . Multiple == RecordFieldMultiple . Default ? "default" : "" ) ,
2526
+ : ( f . Multiple == RecordFieldMultiple . Always ? "default" : "" ) ,
2479
2527
f . Type ? . Description ?? "" ) ;
2480
2528
}
2481
2529
}
@@ -2534,8 +2582,18 @@ private Task RecordTypeInfoCommand(RecordTypeInfoOptions options)
2534
2582
{
2535
2583
if ( typeof ( IFieldTypeSerialize ) . IsAssignableFrom ( fieldInfo . Type . Type ) )
2536
2584
{
2537
- IFieldTypeSerialize fts = ( IFieldTypeSerialize ) Activator . CreateInstance ( fieldInfo . Type . Type ) ;
2538
- table . AddRow ( "Value Elements:" , string . Join ( ", " , fts . Elements . Select ( x => $ "\" { x } \" ") ) ) ;
2585
+ var elements = new List < string > ( ) ;
2586
+ var properties = fieldInfo . Type . Type . GetProperties ( ) ;
2587
+ foreach ( var prop in properties )
2588
+ {
2589
+ var attribute = prop . GetCustomAttribute < DataMemberAttribute > ( true ) ;
2590
+ if ( attribute != null )
2591
+ {
2592
+ elements . Add ( attribute . Name ) ;
2593
+ }
2594
+ }
2595
+
2596
+ table . AddRow ( "Value Elements:" , string . Join ( ", " , elements . Select ( x => $ "\" { x } \" ") ) ) ;
2539
2597
}
2540
2598
}
2541
2599
}
@@ -2901,6 +2959,12 @@ class MakeFolderOptions : FolderOptions
2901
2959
public bool ? CanEdit { get ; set ; }
2902
2960
}
2903
2961
2962
+ class ImportCommandOptions
2963
+ {
2964
+ [ Value ( 0 , Required = true , HelpText = "JSON import filename" ) ]
2965
+ public string FileName { get ; set ; }
2966
+ }
2967
+
2904
2968
class SecretManagerOptions
2905
2969
{
2906
2970
[ Option ( "folder" , Required = false , HelpText = "Shared Folder UID or name. \" share\" , \" unshare\" only" ) ]
0 commit comments