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.
@@ -609,41 +609,199 @@ export const transferUsersLocalToRemote = async (
609
609
  ? converterFunctions.convertPhoneStringToUSInternational(user.phone)
610
610
  : undefined;
611
611
 
612
- if (user.hash) {
613
- await tryAwaitWithRetry(async () =>
614
- remoteUsers.createArgon2User(
615
- user.$id,
616
- user.email,
617
- user.password!, // password - cannot transfer hashed passwords
618
- user.name // phone - optional
619
- )
620
- );
621
- if (phone) {
622
- await tryAwaitWithRetry(async () =>
623
- remoteUsers.updatePhone(user.$id, phone)
624
- );
625
- }
626
- if (user.labels && user.labels.length > 0) {
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.updateLabels(user.$id, user.labels)
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, // phone - optional
637
- user.password, // password - cannot transfer hashed passwords
782
+ phone,
783
+ tempPassword,
638
784
  user.name
639
785
  )
640
786
  );
641
- if (user.labels && user.labels.length > 0) {
642
- await tryAwaitWithRetry(async () =>
643
- remoteUsers.updateLabels(user.$id, user.labels)
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 () =>