appwrite-utils-cli 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +116 -0
- package/dist/interactiveCLI.d.ts +1 -0
- package/dist/interactiveCLI.js +171 -4
- package/dist/migrations/comprehensiveTransfer.d.ts +66 -0
- package/dist/migrations/comprehensiveTransfer.js +366 -0
- package/dist/migrations/transfer.js +82 -13
- package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +4 -4
- package/package.json +1 -1
- package/src/interactiveCLI.ts +182 -4
- package/src/migrations/comprehensiveTransfer.ts +505 -0
- package/src/migrations/transfer.ts +180 -22
@@ -609,41 +609,199 @@ export const transferUsersLocalToRemote = async (
|
|
609
609
|
? converterFunctions.convertPhoneStringToUSInternational(user.phone)
|
610
610
|
: undefined;
|
611
611
|
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
612
|
+
// Handle user creation based on hash type
|
613
|
+
if (user.hash && user.password) {
|
614
|
+
// User has a hashed password - recreate with proper hash method
|
615
|
+
const hashType = user.hash.toLowerCase();
|
616
|
+
const hashedPassword = user.password; // This is already hashed
|
617
|
+
const hashOptions = (user.hashOptions as Record<string, any>) || {};
|
618
|
+
|
619
|
+
try {
|
620
|
+
switch (hashType) {
|
621
|
+
case 'argon2':
|
622
|
+
await tryAwaitWithRetry(async () =>
|
623
|
+
remoteUsers.createArgon2User(
|
624
|
+
user.$id,
|
625
|
+
user.email,
|
626
|
+
hashedPassword,
|
627
|
+
user.name
|
628
|
+
)
|
629
|
+
);
|
630
|
+
break;
|
631
|
+
|
632
|
+
case 'bcrypt':
|
633
|
+
await tryAwaitWithRetry(async () =>
|
634
|
+
remoteUsers.createBcryptUser(
|
635
|
+
user.$id,
|
636
|
+
user.email,
|
637
|
+
hashedPassword,
|
638
|
+
user.name
|
639
|
+
)
|
640
|
+
);
|
641
|
+
break;
|
642
|
+
|
643
|
+
case 'scrypt':
|
644
|
+
// Scrypt requires additional parameters from hashOptions
|
645
|
+
const salt = typeof hashOptions.salt === 'string' ? hashOptions.salt : '';
|
646
|
+
const costCpu = typeof hashOptions.costCpu === 'number' ? hashOptions.costCpu : 32768;
|
647
|
+
const costMemory = typeof hashOptions.costMemory === 'number' ? hashOptions.costMemory : 14;
|
648
|
+
const costParallel = typeof hashOptions.costParallel === 'number' ? hashOptions.costParallel : 1;
|
649
|
+
const length = typeof hashOptions.length === 'number' ? hashOptions.length : 64;
|
650
|
+
|
651
|
+
// Warn if using default values due to missing hash options
|
652
|
+
if (!hashOptions.salt || typeof hashOptions.costCpu !== 'number') {
|
653
|
+
console.log(chalk.yellow(`User ${user.$id}: Using default Scrypt parameters due to missing hashOptions`));
|
654
|
+
}
|
655
|
+
|
656
|
+
await tryAwaitWithRetry(async () =>
|
657
|
+
remoteUsers.createScryptUser(
|
658
|
+
user.$id,
|
659
|
+
user.email,
|
660
|
+
hashedPassword,
|
661
|
+
salt,
|
662
|
+
costCpu,
|
663
|
+
costMemory,
|
664
|
+
costParallel,
|
665
|
+
length,
|
666
|
+
user.name
|
667
|
+
)
|
668
|
+
);
|
669
|
+
break;
|
670
|
+
|
671
|
+
case 'scryptmodified':
|
672
|
+
// Scrypt Modified (Firebase) requires salt, separator, and signer key
|
673
|
+
const modSalt = typeof hashOptions.salt === 'string' ? hashOptions.salt : '';
|
674
|
+
const saltSeparator = typeof hashOptions.saltSeparator === 'string' ? hashOptions.saltSeparator : '';
|
675
|
+
const signerKey = typeof hashOptions.signerKey === 'string' ? hashOptions.signerKey : '';
|
676
|
+
|
677
|
+
// Warn if critical parameters are missing
|
678
|
+
if (!hashOptions.salt || !hashOptions.saltSeparator || !hashOptions.signerKey) {
|
679
|
+
console.log(chalk.yellow(`User ${user.$id}: Missing critical Scrypt Modified parameters in hashOptions`));
|
680
|
+
}
|
681
|
+
|
682
|
+
await tryAwaitWithRetry(async () =>
|
683
|
+
remoteUsers.createScryptModifiedUser(
|
684
|
+
user.$id,
|
685
|
+
user.email,
|
686
|
+
hashedPassword,
|
687
|
+
modSalt,
|
688
|
+
saltSeparator,
|
689
|
+
signerKey,
|
690
|
+
user.name
|
691
|
+
)
|
692
|
+
);
|
693
|
+
break;
|
694
|
+
|
695
|
+
case 'md5':
|
696
|
+
await tryAwaitWithRetry(async () =>
|
697
|
+
remoteUsers.createMD5User(
|
698
|
+
user.$id,
|
699
|
+
user.email,
|
700
|
+
hashedPassword,
|
701
|
+
user.name
|
702
|
+
)
|
703
|
+
);
|
704
|
+
break;
|
705
|
+
|
706
|
+
case 'sha':
|
707
|
+
case 'sha1':
|
708
|
+
case 'sha256':
|
709
|
+
case 'sha512':
|
710
|
+
// SHA variants - determine version from hash type
|
711
|
+
const getPasswordHashVersion = (hash: string) => {
|
712
|
+
switch (hash.toLowerCase()) {
|
713
|
+
case 'sha1': return 'sha1' as any;
|
714
|
+
case 'sha256': return 'sha256' as any;
|
715
|
+
case 'sha512': return 'sha512' as any;
|
716
|
+
default: return 'sha256' as any; // Default to SHA256
|
717
|
+
}
|
718
|
+
};
|
719
|
+
|
720
|
+
await tryAwaitWithRetry(async () =>
|
721
|
+
remoteUsers.createSHAUser(
|
722
|
+
user.$id,
|
723
|
+
user.email,
|
724
|
+
hashedPassword,
|
725
|
+
getPasswordHashVersion(hashType),
|
726
|
+
user.name
|
727
|
+
)
|
728
|
+
);
|
729
|
+
break;
|
730
|
+
|
731
|
+
case 'phpass':
|
732
|
+
await tryAwaitWithRetry(async () =>
|
733
|
+
remoteUsers.createPHPassUser(
|
734
|
+
user.$id,
|
735
|
+
user.email,
|
736
|
+
hashedPassword,
|
737
|
+
user.name
|
738
|
+
)
|
739
|
+
);
|
740
|
+
break;
|
741
|
+
|
742
|
+
default:
|
743
|
+
console.log(chalk.yellow(`Unknown hash type '${hashType}' for user ${user.$id}, falling back to Argon2`));
|
744
|
+
await tryAwaitWithRetry(async () =>
|
745
|
+
remoteUsers.createArgon2User(
|
746
|
+
user.$id,
|
747
|
+
user.email,
|
748
|
+
hashedPassword,
|
749
|
+
user.name
|
750
|
+
)
|
751
|
+
);
|
752
|
+
break;
|
753
|
+
}
|
754
|
+
|
755
|
+
console.log(chalk.green(`User ${user.$id} created with preserved ${hashType} password`));
|
756
|
+
|
757
|
+
} catch (error) {
|
758
|
+
console.log(chalk.yellow(`Failed to create user ${user.$id} with ${hashType} hash, trying with temporary password`));
|
759
|
+
|
760
|
+
// Fallback to creating user with temporary password
|
627
761
|
await tryAwaitWithRetry(async () =>
|
628
|
-
remoteUsers.
|
762
|
+
remoteUsers.create(
|
763
|
+
user.$id,
|
764
|
+
user.email,
|
765
|
+
phone,
|
766
|
+
`changeMe${user.email}`,
|
767
|
+
user.name
|
768
|
+
)
|
629
769
|
);
|
770
|
+
|
771
|
+
console.log(chalk.yellow(`User ${user.$id} created with temporary password - password reset required`));
|
630
772
|
}
|
773
|
+
|
631
774
|
} else {
|
775
|
+
// No hash or password - create with temporary password
|
776
|
+
const tempPassword = user.password || `changeMe${user.email}`;
|
777
|
+
|
632
778
|
await tryAwaitWithRetry(async () =>
|
633
779
|
remoteUsers.create(
|
634
780
|
user.$id,
|
635
781
|
user.email,
|
636
|
-
phone,
|
637
|
-
|
782
|
+
phone,
|
783
|
+
tempPassword,
|
638
784
|
user.name
|
639
785
|
)
|
640
786
|
);
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
);
|
787
|
+
|
788
|
+
if (!user.password) {
|
789
|
+
console.log(chalk.yellow(`User ${user.$id} created with temporary password - password reset required`));
|
645
790
|
}
|
646
791
|
}
|
792
|
+
|
793
|
+
// Update phone, labels, and other attributes
|
794
|
+
if (phone) {
|
795
|
+
await tryAwaitWithRetry(async () =>
|
796
|
+
remoteUsers.updatePhone(user.$id, phone)
|
797
|
+
);
|
798
|
+
}
|
799
|
+
|
800
|
+
if (user.labels && user.labels.length > 0) {
|
801
|
+
await tryAwaitWithRetry(async () =>
|
802
|
+
remoteUsers.updateLabels(user.$id, user.labels)
|
803
|
+
);
|
804
|
+
}
|
647
805
|
|
648
806
|
// Update user preferences and status
|
649
807
|
await tryAwaitWithRetry(async () =>
|