@digitraffic/common 2025.4.29-1 → 2025.5.28-1

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 CHANGED
@@ -17,6 +17,10 @@ Format code
17
17
  pnpm run:format-changed # Formats stagged files
18
18
  pnpm run:format # Format all files
19
19
 
20
+ ## Reinstall lefthook git hooks
21
+
22
+ pnpm prepare
23
+
20
24
  ## How to use
21
25
 
22
26
  In package.json dependencies:
@@ -21,8 +21,13 @@ describe("acl-builder tests", () => {
21
21
  ]).build();
22
22
  expect(acl.rules).toHaveLength(2);
23
23
  });
24
- test("ip restriction", () => {
25
- const acl = createBuilder().withIpRestrictionRule(["1.2.3.4", "1.2.6.6"])
24
+ test("ip blacklist", () => {
25
+ const acl = createBuilder().withIpBlacklistRule(["1.2.3.4", "1.2.6.6"])
26
+ .build();
27
+ expect(acl.rules).toHaveLength(1);
28
+ });
29
+ test("ip whitelist", () => {
30
+ const acl = createBuilder().withIpWhitelistRule(["1.2.3.4", "1.2.6.6"])
26
31
  .build();
27
32
  expect(acl.rules).toHaveLength(1);
28
33
  });
@@ -12,7 +12,7 @@ export type CfnWebAclRuleProperty = {
12
12
  *
13
13
  * Currently supports:
14
14
  * * Some AWS managed WAF rules
15
- * * IP blacklisting
15
+ * * IP blacklisting/whitelisting
16
16
  */
17
17
  export declare class AclBuilder {
18
18
  readonly _construct: Construct;
@@ -23,18 +23,25 @@ export declare class AclBuilder {
23
23
  _customResponseBodies: Record<string, CfnWebACL.CustomResponseBodyProperty>;
24
24
  constructor(construct: Construct, name?: string);
25
25
  isRuleDefined(rules: AWSManagedWafRule[] | "all", rule: AWSManagedWafRule): boolean;
26
- withAWSManagedRules(rules?: AWSManagedWafRule[] | "all", excludedRules?: ExcludedAWSRules): AclBuilder;
27
- withIpRestrictionRule(addresses: string[]): AclBuilder;
28
- withThrottleRule(name: string, limit: number, isHeaderRequired: boolean, isBasedOnIpAndUriPath: boolean, customResponseBodyKey?: string): AclBuilder;
29
- withCustomResponseBody(key: string, customResponseBody: CfnWebACL.CustomResponseBodyProperty): AclBuilder;
30
- withThrottleDigitrafficUserIp(limit: number | undefined): AclBuilder;
31
- withThrottleDigitrafficUserIpAndUriPath(limit: number | undefined): AclBuilder;
26
+ withAWSManagedRules(rules?: AWSManagedWafRule[] | "all", excludedRules?: ExcludedAWSRules): this;
27
+ /**
28
+ * Block access from given addresses
29
+ */
30
+ withIpBlacklistRule(addresses: string[]): this;
31
+ /**
32
+ * Allow access only from the given addresses
33
+ */
34
+ withIpWhitelistRule(addresses: string[]): this;
35
+ withThrottleRule(name: string, limit: number, isHeaderRequired: boolean, isBasedOnIpAndUriPath: boolean, customResponseBodyKey?: string): this;
36
+ withCustomResponseBody(key: string, customResponseBody: CfnWebACL.CustomResponseBodyProperty): this;
37
+ withThrottleDigitrafficUserIp(limit: number | undefined): this;
38
+ withThrottleDigitrafficUserIpAndUriPath(limit: number | undefined): this;
32
39
  withThrottleAnonymousUserIp(limit: number | undefined): AclBuilder;
33
- withThrottleAnonymousUserIpAndUriPath(limit: number | undefined): AclBuilder;
34
- withCountDigitrafficUserIp(limit: number | undefined): AclBuilder;
35
- withCountDigitrafficUserIpAndUriPath(limit: number | undefined): AclBuilder;
36
- withCountAnonymousUserIp(limit: number | undefined): AclBuilder;
37
- withCountAnonymousUserIpAndUriPath(limit: number | undefined): AclBuilder;
40
+ withThrottleAnonymousUserIpAndUriPath(limit: number | undefined): this;
41
+ withCountDigitrafficUserIp(limit: number | undefined): this;
42
+ withCountDigitrafficUserIpAndUriPath(limit: number | undefined): this;
43
+ withCountAnonymousUserIp(limit: number | undefined): this;
44
+ withCountAnonymousUserIpAndUriPath(limit: number | undefined): this;
38
45
  _isCustomResponseBodyKeySet(key: string): boolean;
39
46
  _addThrottleResponseBody(customResponseBodyKey: string, limit: number): void;
40
47
  build(): CfnWebACL;
@@ -6,7 +6,7 @@ import { concat, range, zipWith } from "lodash-es";
6
6
  *
7
7
  * Currently supports:
8
8
  * * Some AWS managed WAF rules
9
- * * IP blacklisting
9
+ * * IP blacklisting/whitelisting
10
10
  */
11
11
  export class AclBuilder {
12
12
  _construct;
@@ -37,7 +37,10 @@ export class AclBuilder {
37
37
  }
38
38
  return this;
39
39
  }
40
- withIpRestrictionRule(addresses) {
40
+ /**
41
+ * Block access from given addresses
42
+ */
43
+ withIpBlacklistRule(addresses) {
41
44
  const blocklistIpSet = new CfnIPSet(this._construct, "BlocklistIpSet", {
42
45
  ipAddressVersion: "IPV4",
43
46
  scope: this._scope,
@@ -59,6 +62,35 @@ export class AclBuilder {
59
62
  });
60
63
  return this;
61
64
  }
65
+ /**
66
+ * Allow access only from the given addresses
67
+ */
68
+ withIpWhitelistRule(addresses) {
69
+ const blocklistIpSet = new CfnIPSet(this._construct, "AllowlistIpSet", {
70
+ ipAddressVersion: "IPV4",
71
+ scope: this._scope,
72
+ addresses,
73
+ });
74
+ this._blockRules.push({
75
+ name: "IpAllowlist",
76
+ action: { block: {} },
77
+ statement: {
78
+ notStatement: {
79
+ statement: {
80
+ ipSetReferenceStatement: {
81
+ arn: blocklistIpSet.attrArn,
82
+ },
83
+ },
84
+ },
85
+ },
86
+ visibilityConfig: {
87
+ sampledRequestsEnabled: false,
88
+ cloudWatchMetricsEnabled: true,
89
+ metricName: "IpAllowlist",
90
+ },
91
+ });
92
+ return this;
93
+ }
62
94
  withThrottleRule(name, limit, isHeaderRequired, isBasedOnIpAndUriPath, customResponseBodyKey) {
63
95
  const isBlockRule = !!customResponseBodyKey;
64
96
  const rules = isBlockRule ? this._blockRules : this._countRules;
@@ -17,7 +17,9 @@ export declare class SecretHolder<Secret extends GenericSecret> {
17
17
  private readonly secretId;
18
18
  private readonly prefix;
19
19
  private readonly expectedKeys;
20
- private readonly secretCache;
20
+ private cachedSecret?;
21
+ private expirationTime;
22
+ private readonly ttl;
21
23
  constructor(secretId: string, prefix?: string, expectedKeys?: string[], configuration?: typeof DEFAULT_CONFIGURATION);
22
24
  private initSecret;
23
25
  static create<S extends GenericSecret>(prefix?: string, expectedKeys?: string[]): SecretHolder<S>;
@@ -2,9 +2,7 @@ import { getSecret } from "./secret.js";
2
2
  import { checkExpectedSecretKeys } from "./dbsecret.js";
3
3
  import { getEnvVariable } from "../../../utils/utils.js";
4
4
  import { logger } from "../dt-logger-default.js";
5
- import NodeTtl from "node-ttl";
6
5
  const DEFAULT_PREFIX = "";
7
- const DEFAULT_SECRET_KEY = "SECRET";
8
6
  const DEFAULT_CONFIGURATION = {
9
7
  ttl: 5 * 60, // timeout secrets in 5 minutes
10
8
  };
@@ -23,12 +21,15 @@ export class SecretHolder {
23
21
  secretId;
24
22
  prefix;
25
23
  expectedKeys;
26
- secretCache;
24
+ cachedSecret;
25
+ expirationTime;
26
+ ttl; // seconds
27
27
  constructor(secretId, prefix = "", expectedKeys = [], configuration = DEFAULT_CONFIGURATION) {
28
28
  this.secretId = secretId;
29
29
  this.prefix = prefix;
30
30
  this.expectedKeys = expectedKeys;
31
- this.secretCache = new NodeTtl(configuration);
31
+ this.expirationTime = new Date(0);
32
+ this.ttl = configuration.ttl;
32
33
  }
33
34
  async initSecret() {
34
35
  const secretValue = await getSecret(this.secretId);
@@ -36,7 +37,8 @@ export class SecretHolder {
36
37
  method: "SecretHolder.initSecret",
37
38
  message: "Refreshing secret " + this.secretId,
38
39
  });
39
- this.secretCache.push(DEFAULT_SECRET_KEY, secretValue);
40
+ this.cachedSecret = secretValue;
41
+ this.expirationTime = new Date(Date.now() + this.ttl * 1000);
40
42
  }
41
43
  static create(prefix = DEFAULT_PREFIX, expectedKeys = []) {
42
44
  return new SecretHolder(getEnvVariable("SECRET_ID"), prefix, expectedKeys);
@@ -67,11 +69,13 @@ export class SecretHolder {
67
69
  return parsed;
68
70
  }
69
71
  async getSecret() {
70
- const secret = this.secretCache.get(DEFAULT_SECRET_KEY);
71
- if (!secret) {
72
+ if (this.expirationTime.getTime() < Date.now()) {
72
73
  await this.initSecret();
73
74
  }
74
- return secret ?? this.secretCache.get(DEFAULT_SECRET_KEY);
75
+ if (this.cachedSecret === undefined) {
76
+ throw new Error("SecretHolder in illegal state");
77
+ }
78
+ return this.cachedSecret;
75
79
  }
76
80
  }
77
81
  //# sourceMappingURL=secret-holder.js.map