hi-secure 1.0.0 → 1.0.3

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.
Files changed (50) hide show
  1. package/dist/adapters/ExpressRLAdapter.d.ts.map +1 -1
  2. package/dist/adapters/ExpressRLAdapter.js +0 -29
  3. package/dist/adapters/ExpressRLAdapter.js.map +1 -1
  4. package/dist/adapters/GoogleAdapter.d.ts.map +1 -1
  5. package/dist/adapters/GoogleAdapter.js +4 -3
  6. package/dist/adapters/GoogleAdapter.js.map +1 -1
  7. package/dist/adapters/JWTAdapter.d.ts.map +1 -1
  8. package/dist/adapters/JWTAdapter.js +3 -1
  9. package/dist/adapters/JWTAdapter.js.map +1 -1
  10. package/dist/core/HiSecure.d.ts +3 -18
  11. package/dist/core/HiSecure.d.ts.map +1 -1
  12. package/dist/core/HiSecure.js +29 -132
  13. package/dist/core/HiSecure.js.map +1 -1
  14. package/dist/core/errors/HttpError.d.ts +17 -0
  15. package/dist/core/errors/HttpError.d.ts.map +1 -0
  16. package/dist/core/errors/HttpError.js +36 -0
  17. package/dist/core/errors/HttpError.js.map +1 -0
  18. package/dist/core/useSecure.d.ts +0 -7
  19. package/dist/core/useSecure.d.ts.map +1 -1
  20. package/dist/core/useSecure.js +65 -21
  21. package/dist/core/useSecure.js.map +1 -1
  22. package/dist/index.d.ts +3 -6
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +19 -9
  25. package/dist/index.js.map +1 -1
  26. package/dist/managers/AuthManager.d.ts.map +1 -1
  27. package/dist/managers/AuthManager.js +18 -17
  28. package/dist/managers/AuthManager.js.map +1 -1
  29. package/dist/managers/ValidatorManager.d.ts +4 -6
  30. package/dist/managers/ValidatorManager.d.ts.map +1 -1
  31. package/dist/managers/ValidatorManager.js +97 -144
  32. package/dist/managers/ValidatorManager.js.map +1 -1
  33. package/dist/middlewares/errorHandler.js +2 -2
  34. package/dist/middlewares/errorHandler.js.map +1 -1
  35. package/dist/utils/normalizeOptions.d.ts.map +1 -1
  36. package/dist/utils/normalizeOptions.js +14 -4
  37. package/dist/utils/normalizeOptions.js.map +1 -1
  38. package/package.json +2 -2
  39. package/readme.md +195 -0
  40. package/src/adapters/ExpressRLAdapter.ts +0 -38
  41. package/src/adapters/GoogleAdapter.ts +5 -3
  42. package/src/adapters/JWTAdapter.ts +3 -1
  43. package/src/core/HiSecure.ts +414 -175
  44. package/src/core/useSecure.ts +91 -36
  45. package/src/index.ts +28 -12
  46. package/src/managers/AuthManager.ts +15 -13
  47. package/src/managers/ValidatorManager.ts +120 -182
  48. package/src/middlewares/errorHandler.ts +1 -1
  49. package/src/utils/normalizeOptions.ts +24 -9
  50. /package/src/core/errors/{HttpErrror.ts → HttpError.ts} +0 -0
@@ -595,7 +595,373 @@
595
595
  // }
596
596
 
597
597
 
598
- // src/core/HiSecure.ts - COMPLETELY FIXED
598
+ // =================
599
+
600
+ // // src/core/HiSecure.ts - COMPLETELY FIXED
601
+ // import { HiSecureConfig } from "./types/HiSecureConfig.js";
602
+ // import { defaultConfig } from "./config.js";
603
+ // import { LIB_NAME, LIB_VERSION } from "./constants.js";
604
+ // import { deepMerge } from "../utils/deepMerge.js";
605
+ // import { deepFreeze } from "../utils/deepFreeze.js";
606
+ // import { logger } from "../logging/index.js";
607
+
608
+ // // Adapters
609
+ // import { ArgonAdapter } from "../adapters/ArgonAdapter.js";
610
+ // import { BcryptAdapter } from "../adapters/BcryptAdapter.js";
611
+ // import { RLFlexibleAdapter } from "../adapters/RLFlexibleAdapter.js";
612
+ // import { ExpressRLAdapter } from "../adapters/ExpressRLAdapter.js";
613
+ // import { ZodAdapter } from "../adapters/ZodAdapter.js";
614
+ // import { ExpressValidatorAdapter } from "../adapters/ExpressValidatorAdapter.js";
615
+ // import { SanitizeHtmlAdapter } from "../adapters/SanitizeHtmlAdapter.js";
616
+ // import { XSSAdapter } from "../adapters/XSSAdapter.js";
617
+
618
+ // // Managers
619
+ // import { HashManager } from "../managers/HashManager.js";
620
+ // import { RateLimitManager } from "../managers/RateLimitManager.js";
621
+ // import { ValidatorManager } from "../managers/ValidatorManager.js";
622
+ // import { SanitizerManager } from "../managers/SanitizerManager.js";
623
+ // import { JsonManager } from "../managers/JsonManager.js";
624
+ // import { CorsManager } from "../managers/CorsManager.js";
625
+ // import { AuthManager } from "../managers/AuthManager.js";
626
+
627
+ // // Middlewares
628
+ // import helmet from "helmet";
629
+ // import hpp from "hpp";
630
+ // import compression from "compression";
631
+ // import { errorHandler } from "../middlewares/errorHandler.js";
632
+
633
+ // // Types
634
+ // import { SecureOptions, ValidationSchema, RateLimitOptions } from "./types/SecureOptions.js";
635
+
636
+ // export class HiSecure {
637
+ // private static instance: HiSecure | null = null;
638
+ // private config: HiSecureConfig;
639
+ // private initialized = false;
640
+
641
+ // // Managers
642
+ // public hashManager!: HashManager;
643
+ // public rateLimitManager!: RateLimitManager;
644
+ // public validatorManager!: ValidatorManager;
645
+ // public sanitizerManager!: SanitizerManager;
646
+ // public jsonManager!: JsonManager;
647
+ // public corsManager!: CorsManager;
648
+ // public authManager?: AuthManager;
649
+
650
+ // // Internal adapters
651
+ // private hashingPrimary: any;
652
+ // private hashingFallback: any;
653
+ // private rateLimiterPrimary: any;
654
+ // private rateLimiterFallback: any;
655
+ // private validatorPrimary: any;
656
+ // private validatorFallback: any;
657
+ // private sanitizerPrimary: any;
658
+ // private sanitizerFallback: any;
659
+
660
+ // // Private constructor for singleton
661
+ // private constructor(userConfig: Partial<HiSecureConfig> = {}) {
662
+ // this.config = deepMerge(defaultConfig, userConfig);
663
+ // }
664
+
665
+ // // =====================================================
666
+ // // SINGLETON & INITIALIZATION
667
+ // // =====================================================
668
+
669
+ // static getInstance(config?: Partial<HiSecureConfig>): HiSecure {
670
+ // if (!HiSecure.instance) {
671
+ // HiSecure.instance = new HiSecure(config);
672
+ // HiSecure.instance.init();
673
+ // }
674
+ // return HiSecure.instance;
675
+ // }
676
+
677
+ // static resetInstance(): void {
678
+ // HiSecure.instance = null;
679
+ // }
680
+
681
+ // init(): void {
682
+ // if (this.initialized) {
683
+ // logger.warn("⚠ HiSecure already initialized");
684
+ // return;
685
+ // }
686
+
687
+ // logger.info(`🔐 ${LIB_NAME} v${LIB_VERSION} initializing...`);
688
+
689
+ // this.setupAdapters();
690
+ // this.setupManagers();
691
+ // this.setupDynamicManagers();
692
+
693
+ // // Make everything immutable
694
+ // deepFreeze(this.config);
695
+ // deepFreeze(this.hashManager);
696
+ // deepFreeze(this.rateLimitManager);
697
+ // deepFreeze(this.validatorManager);
698
+ // deepFreeze(this.sanitizerManager);
699
+ // deepFreeze(this.jsonManager);
700
+ // deepFreeze(this.corsManager);
701
+ // if (this.authManager) deepFreeze(this.authManager);
702
+
703
+ // this.initialized = true;
704
+ // logger.info("✅ HiSecure initialized successfully");
705
+ // }
706
+
707
+ // isInitialized(): boolean {
708
+ // return this.initialized;
709
+ // }
710
+
711
+ // // =====================================================
712
+ // // FLUENT API METHODS (Route-level security)
713
+ // // =====================================================
714
+
715
+ // static auth(options?: { required?: boolean; roles?: string[] }) {
716
+ // const instance = this.getInstance();
717
+ // if (!instance.authManager) {
718
+ // throw new Error("Auth not enabled. Set auth.enabled=true in config.");
719
+ // }
720
+ // return instance.authManager.protect(options);
721
+ // }
722
+
723
+ // static validate(schema: ValidationSchema) {
724
+ // return this.getInstance().validatorManager.validate(schema);
725
+ // }
726
+
727
+ // static sanitize(options?: any) {
728
+ // return this.getInstance().sanitizerManager.middleware(options);
729
+ // }
730
+
731
+ // static rateLimit(preset: "strict" | "relaxed" | "api" | object) {
732
+ // const instance = this.getInstance();
733
+
734
+ // if (typeof preset === "string") {
735
+ // const presets: Record<string, { mode?: "strict" | "relaxed" | "api"; options?: any }> = {
736
+ // strict: { mode: "strict" },
737
+ // relaxed: { mode: "relaxed" },
738
+ // api: { mode: "api", options: { max: 100, windowMs: 60000 } }
739
+ // };
740
+ // return instance.rateLimitManager.middleware(presets[preset] || {});
741
+ // }
742
+
743
+ // return instance.rateLimitManager.middleware({ options: preset });
744
+ // }
745
+
746
+ // static cors(options?: any) {
747
+ // return this.getInstance().corsManager.middleware(options);
748
+ // }
749
+
750
+ // static json(options?: any) {
751
+ // const instance = this.getInstance();
752
+ // const chain = [];
753
+ // chain.push(instance.jsonManager.middleware(options));
754
+ // chain.push(instance.jsonManager.urlencoded());
755
+ // return chain;
756
+ // }
757
+
758
+ // // =====================================================
759
+ // // UTILITY METHODS (Direct usage)
760
+ // // =====================================================
761
+
762
+ // static async hash(password: string): Promise<string> {
763
+ // const instance = this.getInstance();
764
+ // const result = await instance.hashManager.hash(password, { allowFallback: true });
765
+ // return result.hash;
766
+ // }
767
+
768
+ // static async verify(password: string, hash: string): Promise<boolean> {
769
+ // return this.getInstance().hashManager.verify(password, hash);
770
+ // }
771
+
772
+ // static jwt = {
773
+ // sign: (payload: object, options?: any) => {
774
+ // const instance = HiSecure.getInstance();
775
+ // if (!instance.authManager) {
776
+ // throw new Error("Auth not enabled");
777
+ // }
778
+ // return instance.authManager.sign(payload, options);
779
+ // },
780
+
781
+ // verify: (token: string) => {
782
+ // const instance = HiSecure.getInstance();
783
+ // if (!instance.authManager) {
784
+ // throw new Error("Auth not enabled");
785
+ // }
786
+ // return instance.authManager.verify(token);
787
+ // },
788
+
789
+ // google: {
790
+ // verifyIdToken: (idToken: string) => {
791
+ // const instance = HiSecure.getInstance();
792
+ // if (!instance.authManager) {
793
+ // throw new Error("Auth not enabled");
794
+ // }
795
+ // return instance.authManager.verifyGoogleIdToken(idToken);
796
+ // }
797
+ // }
798
+ // };
799
+
800
+ // // =====================================================
801
+ // // GLOBAL MIDDLEWARE (app.use())
802
+ // // =====================================================
803
+
804
+ // static middleware(options?: SecureOptions | "api" | "strict" | "public") {
805
+ // const instance = this.getInstance();
806
+
807
+ // // Handle preset strings
808
+ // if (typeof options === "string") {
809
+ // const presets: Record<string, SecureOptions> = {
810
+ // api: { cors: true, rateLimit: "relaxed" as any, sanitize: true },
811
+ // strict: { cors: true, rateLimit: "strict" as any, sanitize: true, auth: true },
812
+ // public: { cors: true, rateLimit: true as any, sanitize: false }
813
+ // };
814
+ // const presetOptions = presets[options];
815
+ // if (presetOptions) {
816
+ // return instance.createMiddlewareChain(presetOptions);
817
+ // }
818
+ // return instance.createMiddlewareChain({});
819
+ // }
820
+
821
+ // return instance.createMiddlewareChain(options || {});
822
+ // }
823
+
824
+ // // =====================================================
825
+ // // INTERNAL METHODS
826
+ // // =====================================================
827
+
828
+ // private setupAdapters(): void {
829
+ // logger.info("🧩 Setting up adapters...");
830
+
831
+ // // Hashing
832
+ // this.hashingPrimary = this.config.hashing.primary === "argon2"
833
+ // ? new ArgonAdapter()
834
+ // : new BcryptAdapter(this.config.hashing.saltRounds);
835
+
836
+ // this.hashingFallback = this.config.hashing.fallback === "bcrypt"
837
+ // ? new BcryptAdapter(this.config.hashing.saltRounds)
838
+ // : null;
839
+
840
+ // // Rate limiting
841
+ // this.rateLimiterPrimary = this.config.rateLimiter.useAdaptiveMode
842
+ // ? new RLFlexibleAdapter()
843
+ // : new ExpressRLAdapter();
844
+ // this.rateLimiterFallback = new ExpressRLAdapter();
845
+
846
+ // // Validation
847
+ // this.validatorPrimary = this.config.validation.mode === "zod"
848
+ // ? new ZodAdapter()
849
+ // : new ExpressValidatorAdapter();
850
+ // this.validatorFallback = this.config.validation.fallback === "express-validator"
851
+ // ? new ExpressValidatorAdapter()
852
+ // : null;
853
+
854
+ // // Sanitization
855
+ // this.sanitizerPrimary = new SanitizeHtmlAdapter(this.config.sanitizer);
856
+ // this.sanitizerFallback = new XSSAdapter(this.config.sanitizer);
857
+
858
+ // logger.info("✅ Adapters ready");
859
+ // }
860
+
861
+ // private setupManagers(): void {
862
+ // this.hashManager = new HashManager(
863
+ // this.config.hashing,
864
+ // this.hashingPrimary,
865
+ // this.hashingFallback
866
+ // );
867
+
868
+ // this.rateLimitManager = new RateLimitManager(
869
+ // this.config.rateLimiter,
870
+ // this.rateLimiterPrimary,
871
+ // this.rateLimiterFallback
872
+ // );
873
+
874
+ // this.validatorManager = new ValidatorManager(
875
+ // // this.config.validation,
876
+ // // this.validatorPrimary,
877
+ // // this.validatorFallback
878
+ // new ZodAdapter(),
879
+ // new ExpressValidatorAdapter()
880
+ // );
881
+
882
+ // this.sanitizerManager = new SanitizerManager(
883
+ // this.sanitizerPrimary,
884
+ // this.sanitizerFallback
885
+ // );
886
+ // }
887
+
888
+ // private setupDynamicManagers(): void {
889
+ // this.jsonManager = new JsonManager();
890
+ // this.corsManager = new CorsManager();
891
+
892
+ // // Auth manager (only if enabled)
893
+ // if (this.config.auth.enabled) {
894
+ // const jwtSecret = process.env.JWT_SECRET || this.config.auth.jwtSecret;
895
+ // if (!jwtSecret) {
896
+ // throw new Error("JWT_SECRET environment variable or jwtSecret in config is required when auth.enabled=true");
897
+ // }
898
+
899
+ // this.authManager = new AuthManager({
900
+ // jwtSecret,
901
+ // jwtExpiresIn: this.config.auth.jwtExpiresIn,
902
+ // googleClientId: process.env.GOOGLE_CLIENT_ID || this.config.auth.googleClientId
903
+ // // Removed algorithm - handled in AuthManager
904
+ // });
905
+ // }
906
+ // }
907
+
908
+ // private createMiddlewareChain(options: SecureOptions): any[] {
909
+ // const chain: any[] = [];
910
+
911
+ // // JSON parsing
912
+ // chain.push(this.jsonManager.middleware(this.config.json));
913
+ // chain.push(this.jsonManager.urlencoded(this.config.urlencoded));
914
+
915
+ // // Security headers
916
+ // if (this.config.enableHelmet) chain.push(helmet());
917
+ // if (this.config.enableHPP) chain.push(hpp());
918
+
919
+ // // Compression (check if compression config exists)
920
+ // if (this.config.enableCompression && this.config.compression) {
921
+ // chain.push(compression(this.config.compression));
922
+ // } else if (this.config.enableCompression) {
923
+ // chain.push(compression()); // Use defaults
924
+ // }
925
+
926
+ // // CORS
927
+ // if (this.config.enableCORS || options.cors) {
928
+ // const corsOptions = options.cors === true ? this.config.cors :
929
+ // (typeof options.cors === 'object' ? options.cors : this.config.cors);
930
+ // chain.push(this.corsManager.middleware(corsOptions));
931
+ // }
932
+
933
+ // // Sanitization
934
+ // if (this.config.enableSanitizer || options.sanitize) {
935
+ // const sanitizeOptions = options.sanitize === true ? undefined :
936
+ // (typeof options.sanitize === 'object' ? options.sanitize : undefined);
937
+ // chain.push(this.sanitizerManager.middleware(sanitizeOptions));
938
+ // }
939
+
940
+ // // Rate limiting
941
+ // if (this.config.enableRateLimiter || options.rateLimit) {
942
+ // const rateLimitOpts = typeof options.rateLimit === 'object' ?
943
+ // { options: options.rateLimit } : {};
944
+ // chain.push(this.rateLimitManager.middleware(rateLimitOpts));
945
+ // }
946
+
947
+ // // Authentication
948
+ // if (options.auth && this.authManager) {
949
+ // const authOpts = options.auth === true ? undefined :
950
+ // (typeof options.auth === 'object' ? options.auth : undefined);
951
+ // chain.push(this.authManager.protect(authOpts));
952
+ // }
953
+
954
+ // // Error handler (always last)
955
+ // chain.push(errorHandler);
956
+
957
+ // return chain;
958
+ // }
959
+ // }
960
+
961
+
962
+ // ===================
963
+
964
+ // src/core/HiSecure.ts - FINAL VERSION
599
965
  import { HiSecureConfig } from "./types/HiSecureConfig.js";
600
966
  import { defaultConfig } from "./config.js";
601
967
  import { LIB_NAME, LIB_VERSION } from "./constants.js";
@@ -629,7 +995,7 @@ import compression from "compression";
629
995
  import { errorHandler } from "../middlewares/errorHandler.js";
630
996
 
631
997
  // Types
632
- import { SecureOptions, ValidationSchema, RateLimitOptions } from "./types/SecureOptions.js";
998
+ import { SecureOptions, ValidationSchema } from "./types/SecureOptions.js";
633
999
 
634
1000
  export class HiSecure {
635
1001
  private static instance: HiSecure | null = null;
@@ -650,20 +1016,14 @@ export class HiSecure {
650
1016
  private hashingFallback: any;
651
1017
  private rateLimiterPrimary: any;
652
1018
  private rateLimiterFallback: any;
653
- private validatorPrimary: any;
654
- private validatorFallback: any;
655
- private sanitizerPrimary: any;
656
- private sanitizerFallback: any;
657
1019
 
658
- // Private constructor for singleton
659
1020
  private constructor(userConfig: Partial<HiSecureConfig> = {}) {
660
1021
  this.config = deepMerge(defaultConfig, userConfig);
661
1022
  }
662
1023
 
663
1024
  // =====================================================
664
- // SINGLETON & INITIALIZATION
1025
+ // SINGLETON
665
1026
  // =====================================================
666
-
667
1027
  static getInstance(config?: Partial<HiSecureConfig>): HiSecure {
668
1028
  if (!HiSecure.instance) {
669
1029
  HiSecure.instance = new HiSecure(config);
@@ -677,10 +1037,7 @@ export class HiSecure {
677
1037
  }
678
1038
 
679
1039
  init(): void {
680
- if (this.initialized) {
681
- logger.warn("⚠ HiSecure already initialized");
682
- return;
683
- }
1040
+ if (this.initialized) return;
684
1041
 
685
1042
  logger.info(`🔐 ${LIB_NAME} v${LIB_VERSION} initializing...`);
686
1043
 
@@ -688,34 +1045,20 @@ export class HiSecure {
688
1045
  this.setupManagers();
689
1046
  this.setupDynamicManagers();
690
1047
 
691
- // Make everything immutable
1048
+ // DO NOT FREEZE MANAGERS
1049
+ // ✔ Only freeze config
692
1050
  deepFreeze(this.config);
693
- deepFreeze(this.hashManager);
694
- deepFreeze(this.rateLimitManager);
695
- deepFreeze(this.validatorManager);
696
- deepFreeze(this.sanitizerManager);
697
- deepFreeze(this.jsonManager);
698
- deepFreeze(this.corsManager);
699
- if (this.authManager) deepFreeze(this.authManager);
700
1051
 
701
1052
  this.initialized = true;
702
1053
  logger.info("✅ HiSecure initialized successfully");
703
1054
  }
704
1055
 
705
- isInitialized(): boolean {
706
- return this.initialized;
707
- }
708
-
709
1056
  // =====================================================
710
- // FLUENT API METHODS (Route-level security)
1057
+ // FLUENT API (Route-level)
711
1058
  // =====================================================
712
-
1059
+
713
1060
  static auth(options?: { required?: boolean; roles?: string[] }) {
714
- const instance = this.getInstance();
715
- if (!instance.authManager) {
716
- throw new Error("Auth not enabled. Set auth.enabled=true in config.");
717
- }
718
- return instance.authManager.protect(options);
1061
+ return this.getInstance().authManager!.protect(options);
719
1062
  }
720
1063
 
721
1064
  static validate(schema: ValidationSchema) {
@@ -726,107 +1069,39 @@ export class HiSecure {
726
1069
  return this.getInstance().sanitizerManager.middleware(options);
727
1070
  }
728
1071
 
1072
+ static cors(options?: any) {
1073
+ return this.getInstance().corsManager.middleware(options);
1074
+ }
1075
+
729
1076
  static rateLimit(preset: "strict" | "relaxed" | "api" | object) {
730
1077
  const instance = this.getInstance();
731
-
1078
+
732
1079
  if (typeof preset === "string") {
733
- const presets: Record<string, { mode?: "strict" | "relaxed" | "api"; options?: any }> = {
1080
+ const presets: any = {
734
1081
  strict: { mode: "strict" },
735
1082
  relaxed: { mode: "relaxed" },
736
1083
  api: { mode: "api", options: { max: 100, windowMs: 60000 } }
737
1084
  };
738
1085
  return instance.rateLimitManager.middleware(presets[preset] || {});
739
1086
  }
740
-
741
1087
  return instance.rateLimitManager.middleware({ options: preset });
742
1088
  }
743
1089
 
744
- static cors(options?: any) {
745
- return this.getInstance().corsManager.middleware(options);
746
- }
747
-
748
1090
  static json(options?: any) {
749
1091
  const instance = this.getInstance();
750
- const chain = [];
751
- chain.push(instance.jsonManager.middleware(options));
752
- chain.push(instance.jsonManager.urlencoded());
753
- return chain;
1092
+ return [
1093
+ instance.jsonManager.middleware(options),
1094
+ instance.jsonManager.urlencoded()
1095
+ ];
754
1096
  }
755
1097
 
756
1098
  // =====================================================
757
- // UTILITY METHODS (Direct usage)
1099
+ // INTERNAL SETUP
758
1100
  // =====================================================
759
-
760
- static async hash(password: string): Promise<string> {
761
- const instance = this.getInstance();
762
- const result = await instance.hashManager.hash(password, { allowFallback: true });
763
- return result.hash;
764
- }
765
-
766
- static async verify(password: string, hash: string): Promise<boolean> {
767
- return this.getInstance().hashManager.verify(password, hash);
768
- }
769
-
770
- static jwt = {
771
- sign: (payload: object, options?: any) => {
772
- const instance = HiSecure.getInstance();
773
- if (!instance.authManager) {
774
- throw new Error("Auth not enabled");
775
- }
776
- return instance.authManager.sign(payload, options);
777
- },
778
-
779
- verify: (token: string) => {
780
- const instance = HiSecure.getInstance();
781
- if (!instance.authManager) {
782
- throw new Error("Auth not enabled");
783
- }
784
- return instance.authManager.verify(token);
785
- },
786
-
787
- google: {
788
- verifyIdToken: (idToken: string) => {
789
- const instance = HiSecure.getInstance();
790
- if (!instance.authManager) {
791
- throw new Error("Auth not enabled");
792
- }
793
- return instance.authManager.verifyGoogleIdToken(idToken);
794
- }
795
- }
796
- };
797
1101
 
798
- // =====================================================
799
- // GLOBAL MIDDLEWARE (app.use())
800
- // =====================================================
801
-
802
- static middleware(options?: SecureOptions | "api" | "strict" | "public") {
803
- const instance = this.getInstance();
804
-
805
- // Handle preset strings
806
- if (typeof options === "string") {
807
- const presets: Record<string, SecureOptions> = {
808
- api: { cors: true, rateLimit: "relaxed" as any, sanitize: true },
809
- strict: { cors: true, rateLimit: "strict" as any, sanitize: true, auth: true },
810
- public: { cors: true, rateLimit: true as any, sanitize: false }
811
- };
812
- const presetOptions = presets[options];
813
- if (presetOptions) {
814
- return instance.createMiddlewareChain(presetOptions);
815
- }
816
- return instance.createMiddlewareChain({});
817
- }
818
-
819
- return instance.createMiddlewareChain(options || {});
820
- }
821
-
822
- // =====================================================
823
- // INTERNAL METHODS
824
- // =====================================================
825
-
826
1102
  private setupAdapters(): void {
827
1103
  logger.info("🧩 Setting up adapters...");
828
1104
 
829
- // Hashing
830
1105
  this.hashingPrimary = this.config.hashing.primary === "argon2"
831
1106
  ? new ArgonAdapter()
832
1107
  : new BcryptAdapter(this.config.hashing.saltRounds);
@@ -835,33 +1110,17 @@ export class HiSecure {
835
1110
  ? new BcryptAdapter(this.config.hashing.saltRounds)
836
1111
  : null;
837
1112
 
838
- // Rate limiting
839
1113
  this.rateLimiterPrimary = this.config.rateLimiter.useAdaptiveMode
840
1114
  ? new RLFlexibleAdapter()
841
1115
  : new ExpressRLAdapter();
842
- this.rateLimiterFallback = new ExpressRLAdapter();
843
-
844
- // Validation
845
- this.validatorPrimary = this.config.validation.mode === "zod"
846
- ? new ZodAdapter()
847
- : new ExpressValidatorAdapter();
848
- this.validatorFallback = this.config.validation.fallback === "express-validator"
849
- ? new ExpressValidatorAdapter()
850
- : null;
851
1116
 
852
- // Sanitization
853
- this.sanitizerPrimary = new SanitizeHtmlAdapter(this.config.sanitizer);
854
- this.sanitizerFallback = new XSSAdapter(this.config.sanitizer);
1117
+ this.rateLimiterFallback = new ExpressRLAdapter();
855
1118
 
856
1119
  logger.info("✅ Adapters ready");
857
1120
  }
858
1121
 
859
1122
  private setupManagers(): void {
860
- this.hashManager = new HashManager(
861
- this.config.hashing,
862
- this.hashingPrimary,
863
- this.hashingFallback
864
- );
1123
+ this.hashManager = new HashManager(this.config.hashing, this.hashingPrimary, this.hashingFallback);
865
1124
 
866
1125
  this.rateLimitManager = new RateLimitManager(
867
1126
  this.config.rateLimiter,
@@ -869,15 +1128,15 @@ export class HiSecure {
869
1128
  this.rateLimiterFallback
870
1129
  );
871
1130
 
1131
+ // ✔ AUTO-DETECT VALIDATION (ZOD + EXPRESS-VALIDATOR)
872
1132
  this.validatorManager = new ValidatorManager(
873
- this.config.validation,
874
- this.validatorPrimary,
875
- this.validatorFallback
1133
+ new ZodAdapter(),
1134
+ new ExpressValidatorAdapter()
876
1135
  );
877
1136
 
878
1137
  this.sanitizerManager = new SanitizerManager(
879
- this.sanitizerPrimary,
880
- this.sanitizerFallback
1138
+ new SanitizeHtmlAdapter(this.config.sanitizer),
1139
+ new XSSAdapter(this.config.sanitizer)
881
1140
  );
882
1141
  }
883
1142
 
@@ -885,71 +1144,51 @@ export class HiSecure {
885
1144
  this.jsonManager = new JsonManager();
886
1145
  this.corsManager = new CorsManager();
887
1146
 
888
- // Auth manager (only if enabled)
889
1147
  if (this.config.auth.enabled) {
890
1148
  const jwtSecret = process.env.JWT_SECRET || this.config.auth.jwtSecret;
891
- if (!jwtSecret) {
892
- throw new Error("JWT_SECRET environment variable or jwtSecret in config is required when auth.enabled=true");
893
- }
1149
+ if (!jwtSecret) throw new Error("JWT_SECRET is required when auth.enabled=true");
894
1150
 
895
1151
  this.authManager = new AuthManager({
896
1152
  jwtSecret,
897
1153
  jwtExpiresIn: this.config.auth.jwtExpiresIn,
898
- googleClientId: process.env.GOOGLE_CLIENT_ID || this.config.auth.googleClientId
899
- // Removed algorithm - handled in AuthManager
1154
+ googleClientId: this.config.auth.googleClientId
900
1155
  });
901
1156
  }
902
1157
  }
903
1158
 
904
1159
  private createMiddlewareChain(options: SecureOptions): any[] {
905
1160
  const chain: any[] = [];
906
-
907
- // JSON parsing
1161
+
908
1162
  chain.push(this.jsonManager.middleware(this.config.json));
909
1163
  chain.push(this.jsonManager.urlencoded(this.config.urlencoded));
910
-
911
- // Security headers
1164
+
912
1165
  if (this.config.enableHelmet) chain.push(helmet());
913
1166
  if (this.config.enableHPP) chain.push(hpp());
914
-
915
- // Compression (check if compression config exists)
916
- if (this.config.enableCompression && this.config.compression) {
917
- chain.push(compression(this.config.compression));
918
- } else if (this.config.enableCompression) {
919
- chain.push(compression()); // Use defaults
920
- }
921
-
922
- // CORS
1167
+
1168
+ if (this.config.enableCompression) chain.push(compression(this.config.compression));
1169
+
923
1170
  if (this.config.enableCORS || options.cors) {
924
- const corsOptions = options.cors === true ? this.config.cors :
925
- (typeof options.cors === 'object' ? options.cors : this.config.cors);
926
- chain.push(this.corsManager.middleware(corsOptions));
1171
+ const opts = typeof options.cors === "object" ? options.cors : this.config.cors;
1172
+ chain.push(this.corsManager.middleware(opts));
927
1173
  }
928
-
929
- // Sanitization
1174
+
930
1175
  if (this.config.enableSanitizer || options.sanitize) {
931
- const sanitizeOptions = options.sanitize === true ? undefined :
932
- (typeof options.sanitize === 'object' ? options.sanitize : undefined);
933
- chain.push(this.sanitizerManager.middleware(sanitizeOptions));
1176
+ const opts = typeof options.sanitize === "object" ? options.sanitize : undefined;
1177
+ chain.push(this.sanitizerManager.middleware(opts));
934
1178
  }
935
-
936
- // Rate limiting
1179
+
937
1180
  if (this.config.enableRateLimiter || options.rateLimit) {
938
- const rateLimitOpts = typeof options.rateLimit === 'object' ?
939
- { options: options.rateLimit } : {};
940
- chain.push(this.rateLimitManager.middleware(rateLimitOpts));
1181
+ const opts = typeof options.rateLimit === "object" ? { options: options.rateLimit } : {};
1182
+ chain.push(this.rateLimitManager.middleware(opts));
941
1183
  }
942
-
943
- // Authentication
1184
+
944
1185
  if (options.auth && this.authManager) {
945
- const authOpts = options.auth === true ? undefined :
946
- (typeof options.auth === 'object' ? options.auth : undefined);
947
- chain.push(this.authManager.protect(authOpts));
1186
+ const opts = typeof options.auth === "object" ? options.auth : undefined;
1187
+ chain.push(this.authManager.protect(opts));
948
1188
  }
949
-
950
- // Error handler (always last)
1189
+
951
1190
  chain.push(errorHandler);
952
-
1191
+
953
1192
  return chain;
954
1193
  }
955
- }
1194
+ }