@donotdev/security 0.0.1 → 0.0.2
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/dist/client/index.js +1 -1
- package/dist/index.js +1 -1
- package/dist/server/AnomalyDetector.js +2 -2
- package/dist/server/AuditLogger.js +2 -2
- package/dist/server/DndevSecurity.d.ts +1 -1
- package/dist/server/DndevSecurity.d.ts.map +1 -1
- package/dist/server/DndevSecurity.js +1 -1
- package/dist/server/PiiEncryptor.js +1 -1
- package/dist/server/PrivacyManager.js +1 -1
- package/dist/server/RateLimiter.d.ts +5 -5
- package/dist/server/RateLimiter.d.ts.map +1 -1
- package/dist/server/RateLimiter.js +1 -1
- package/dist/server/SecretValidator.js +1 -1
- package/dist/server/index.d.ts +3 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/package.json +3 -3
package/dist/client/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{HealthMonitor as
|
|
1
|
+
import{HealthMonitor as o}from"./HealthMonitor";import{AuthHardening as t}from"../common/AuthHardening";export{t as AuthHardening,o as HealthMonitor};
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{HealthMonitor as
|
|
1
|
+
import{HealthMonitor as o}from"./client/HealthMonitor";import{AuthHardening as t}from"./common/AuthHardening";export{t as AuthHardening,o as HealthMonitor};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const
|
|
2
|
-
`)})}record(t,
|
|
1
|
+
const l=1e4;class i{counters=new Map;thresholds;onAnomaly;constructor(t={},r){this.thresholds={authFailures:t.authFailures??10,bulkDeletes:t.bulkDeletes??50,bulkReads:t.bulkReads??1e3,bulkExports:t.bulkExports??5,rateLimitExceeded:t.rateLimitExceeded??10,windowMs:t.windowMs??6e4},this.onAnomaly=r??((s,e,o)=>{process.stderr.write(JSON.stringify({level:"warn",service:"dndev-anomaly",type:"anomaly.detected",anomalyType:s,count:e,userId:o,timestamp:new Date().toISOString()})+`
|
|
2
|
+
`)})}record(t,r){const s=`${t}:${r??"__global__"}`,e=Date.now();!this.counters.has(s)&&this.counters.size>=1e4&&this._evictExpired(e);const o=this.counters.get(s)??{count:0,windowStart:e};e-o.windowStart>this.thresholds.windowMs&&(o.count=0,o.windowStart=e),o.count+=1,this.counters.set(s,o);const n=this.getThreshold(t);o.count===n&&this.onAnomaly(t,o.count,r)}getThreshold(t){switch(t){case"auth.failures":return this.thresholds.authFailures;case"bulk.deletes":return this.thresholds.bulkDeletes;case"bulk.reads":return this.thresholds.bulkReads;case"bulk.exports":return this.thresholds.bulkExports;case"rate_limit.exceeded":return this.thresholds.rateLimitExceeded}}_evictExpired(t){for(const[r,s]of this.counters)t-s.windowStart>this.thresholds.windowMs&&this.counters.delete(r)}getCount(t,r){const s=`${t}:${r??"__global__"}`,e=this.counters.get(s);return!e||Date.now()-e.windowStart>this.thresholds.windowMs?0:e.count}}export{i as AnomalyDetector};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{scrubSecrets as s}from"./SecretValidator";class
|
|
2
|
-
`)})}log(t){const e=s(t),i={level:this.level,service:this.service,...e,timestamp:e.timestamp??new Date().toISOString()};this.write(i)}}export{
|
|
1
|
+
import{scrubSecrets as s}from"./SecretValidator";class r{service;level;write;constructor(t={}){this.service=t.service??"dndev",this.level=t.level??"info",this.write=t.write??(e=>{let i;try{i=JSON.stringify(e)}catch{i=JSON.stringify({level:e.level,service:e.service,type:e.type,timestamp:e.timestamp,_serializeError:"Audit entry contained non-serializable values"})}process.stdout.write(i+`
|
|
2
|
+
`)})}log(t){const e=s(t),i={level:this.level,service:this.service,...e,timestamp:e.timestamp??new Date().toISOString()};this.write(i)}}export{r as AuditLogger};
|
|
@@ -29,7 +29,7 @@ export interface DndevSecurityConfig {
|
|
|
29
29
|
* Store in your secret manager — never in code.
|
|
30
30
|
*/
|
|
31
31
|
piiSecret?: string;
|
|
32
|
-
/** PII encryption salt
|
|
32
|
+
/** PII encryption salt — required when piiSecret is set (no default) */
|
|
33
33
|
piiSalt?: string;
|
|
34
34
|
/** Rate limiter options (default: 100 writes/min, 500 reads/min) */
|
|
35
35
|
rateLimit?: RateLimiterOptions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DndevSecurity.d.ts","sourceRoot":"","sources":["../../src/server/DndevSecurity.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"DndevSecurity.d.ts","sourceRoot":"","sources":["../../src/server/DndevSecurity.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AuditLogger as
|
|
1
|
+
import{AuditLogger as o}from"./AuditLogger";import{DndevRateLimiter as c}from"./RateLimiter";import{PiiEncryptor as s}from"./PiiEncryptor";import{AuthHardening as d}from"./AuthHardening";import{AnomalyDetector as m}from"./AnomalyDetector";import{PrivacyManager as p}from"./PrivacyManager";class r{auditLogger;rateLimiter;piiEncryptor;authHardening;anomalyDetector;privacyManager;_rateLimitBackend;_backendWriteConfig;_backendReadConfig;constructor(t={}){if(this.auditLogger=new o(t.logger),this.rateLimiter=new c(t.rateLimit),t.piiSecret&&!t.piiSalt)throw new Error("[dndev/security] DndevSecurity: PII encryption requires both piiSecret and piiSalt configuration. Provide a per-deployment unique salt stored in your secret manager.");this.piiEncryptor=t.piiSecret&&t.piiSalt?new s(t.piiSecret,t.piiSalt):null,this.authHardening=new d(t.auth),this.anomalyDetector=new m(t.anomaly,t.anomaly?.onAnomaly),this.privacyManager=new p(t.retention),this._rateLimitBackend=t.rateLimitBackend;const i=(t.rateLimit?.writes?.durationSeconds??60)*1e3,e=(t.rateLimit?.reads?.durationSeconds??60)*1e3;this._backendWriteConfig={maxAttempts:t.rateLimit?.writes?.points??100,windowMs:i,blockDurationMs:i},this._backendReadConfig={maxAttempts:t.rateLimit?.reads?.points??500,windowMs:e,blockDurationMs:e}}audit(t){this.auditLogger.log(t)}async checkRateLimit(t,i){if(this._rateLimitBackend){const e=i==="write"?this._backendWriteConfig:this._backendReadConfig,a=await this._rateLimitBackend.check(t,e);if(!a.allowed){this.anomalyDetector.record("rate_limit.exceeded",t);const n=a.blockRemainingSeconds??"a few";throw new Error(`Rate limit exceeded. Try again in ${n} seconds.`)}return}try{await this.rateLimiter.check(t,i)}catch(e){throw this.anomalyDetector.record("rate_limit.exceeded",t),e}}encryptPii(t,i){return!this.piiEncryptor||i.length===0?t:this.piiEncryptor.encryptFields(t,i)}decryptPii(t,i){return!this.piiEncryptor||i.length===0?t:this.piiEncryptor.decryptFields(t,i)}static VALID_ANOMALY_TYPES=new Set(["auth.failures","bulk.deletes","bulk.reads","bulk.exports","rate_limit.exceeded"]);recordAnomaly(t,i){if(!r.VALID_ANOMALY_TYPES.has(t))throw new Error(`[dndev/security] DndevSecurity: unknown anomaly type "${t}". Valid types: ${[...r.VALID_ANOMALY_TYPES].join(", ")}`);this.anomalyDetector.record(t,i)}}export{r as DndevSecurity};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createCipheriv as
|
|
1
|
+
import{createCipheriv as l,createDecipheriv as u,randomBytes as y,scryptSync as g}from"node:crypto";const f="aes-256-gcm",m=32,i=12,d=16,o="dnpii1:";class E{key;constructor(t,e){if(!t||t.length<32)throw new Error("[dndev/security] PiiEncryptor: secret must be at least 32 characters");if(!e||e.length<8)throw new Error("[dndev/security] PiiEncryptor: salt is required and must be at least 8 characters. Use a per-deployment secret stored in your secret manager \u2014 never a hard-coded value.");this.key=g(t,e,m,{N:65536,r:8,p:1})}encrypt(t){const e=y(i),r=l(f,this.key,e),s=Buffer.concat([r.update(t,"utf8"),r.final()]),n=r.getAuthTag();return`${o}${e.toString("hex")}:${n.toString("hex")}:${s.toString("hex")}`}decrypt(t){const e=(t.startsWith(o)?t.slice(o.length):t).split(":");if(e.length!==3)throw new Error("[dndev/security] PiiEncryptor: invalid ciphertext format");const[r,s,n]=e,c=Buffer.from(r,"hex"),h=Buffer.from(s,"hex"),p=Buffer.from(n,"hex");if(c.length!==i)throw new Error(`[dndev/security] PiiEncryptor: invalid IV length ${c.length}, expected ${i}`);if(h.length!==d)throw new Error(`[dndev/security] PiiEncryptor: invalid auth tag length ${h.length}, expected ${d}`);const a=u(f,this.key,c);return a.setAuthTag(h),a.update(p).toString("utf8")+a.final("utf8")}encryptFields(t,e){if(e.length===0)return t;const r={...t};for(const s of e){const n=r[s];typeof n=="string"&&(r[s]=this.encrypt(n))}return r}isEncrypted(t){if(t.startsWith(o))return!0;const e=t.split(":");if(e.length!==3)return!1;const[r,s]=e,n=/^[0-9a-f]+$/i;return r.length===i*2&&s.length===d*2&&n.test(r)&&n.test(s)}dispose(){this.key.fill(0)}[Symbol.dispose](){this.dispose()}decryptFields(t,e){if(e.length===0)return t;const r={...t};for(const s of e){const n=r[s];typeof n=="string"&&this.isEncrypted(n)&&(r[s]=this.decrypt(n))}return r}}export{E as PiiEncryptor};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
class
|
|
1
|
+
class c{policies;constructor(e=[]){this.policies=e}async eraseUser(e){if(e.collections.length===0)throw new Error("[dndev/security] eraseUser: collections array is empty. Provide at least one collection to erase user data from. A no-op erasure silently violates GDPR Art. 17.");const r=[],t=[];for(const s of e.collections)try{await e.deleteUserData(s,e.userId),r.push(s)}catch(o){t.push({collection:s,message:o instanceof Error?o.message:String(o)})}return{erased:r,errors:t}}shouldPurge(e,r){const t=this.policies.find(n=>n.collection===e);if(!t||t.days===0)return!1;if(!r)throw new Error(`[dndev/security] shouldPurge: missing dateIso for collection "${e}". Expected ISO 8601 string. Cannot determine if document should be purged.`);const s=new Date(r).getTime();if(isNaN(s))throw new Error(`[dndev/security] shouldPurge: invalid dateIso "${r}" for collection "${e}". Expected ISO 8601 string. Cannot determine if document should be purged.`);const o=Date.now()-s,i=t.days*24*60*60*1e3;return o>i}getPolicies(){return this.policies}}export{c as PrivacyManager};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* briefly double the effective rate. Use a Redis-backed backend with a true
|
|
9
9
|
* sliding-window for strict rate control in production.
|
|
10
10
|
*
|
|
11
|
-
* For distributed (multi-replica) deployments, implement
|
|
11
|
+
* For distributed (multi-replica) deployments, implement RateLimitStorageBackend
|
|
12
12
|
* and provide a Redis-backed implementation.
|
|
13
13
|
*
|
|
14
14
|
* @version 0.0.1
|
|
@@ -28,7 +28,7 @@ export interface RateLimitWindow {
|
|
|
28
28
|
* @since 0.0.1
|
|
29
29
|
* @author AMBROISE PARK Consulting
|
|
30
30
|
*/
|
|
31
|
-
export interface
|
|
31
|
+
export interface RateLimitStorageBackend {
|
|
32
32
|
increment(key: string, windowMs: number): Promise<number>;
|
|
33
33
|
reset(key: string): Promise<void>;
|
|
34
34
|
}
|
|
@@ -41,7 +41,7 @@ export interface RateLimiterBackend {
|
|
|
41
41
|
* @since 0.0.1
|
|
42
42
|
* @author AMBROISE PARK Consulting
|
|
43
43
|
*/
|
|
44
|
-
export declare class
|
|
44
|
+
export declare class MemoryRateLimitStorageBackend implements RateLimitStorageBackend {
|
|
45
45
|
private readonly store;
|
|
46
46
|
increment(key: string, windowMs: number): Promise<number>;
|
|
47
47
|
reset(key: string): Promise<void>;
|
|
@@ -50,8 +50,8 @@ export declare class MemoryRateLimiterBackend implements RateLimiterBackend {
|
|
|
50
50
|
export interface RateLimiterOptions {
|
|
51
51
|
writes?: Partial<RateLimitWindow>;
|
|
52
52
|
reads?: Partial<RateLimitWindow>;
|
|
53
|
-
/** Custom backend (default:
|
|
54
|
-
backend?:
|
|
53
|
+
/** Custom backend (default: MemoryRateLimitStorageBackend) */
|
|
54
|
+
backend?: RateLimitStorageBackend;
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
57
57
|
* Rate limiter with separate write/read limits (SOC2 CC6.6).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RateLimiter.d.ts","sourceRoot":"","sources":["../../src/server/RateLimiter.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,eAAe;IAC9B,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,eAAe,EAAE,MAAM,CAAC;CACzB;AASD;;;;;;GAMG;AACH,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"RateLimiter.d.ts","sourceRoot":"","sources":["../../src/server/RateLimiter.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,eAAe;IAC9B,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,eAAe,EAAE,MAAM,CAAC;CACzB;AASD;;;;;;GAMG;AACH,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC;AAKD;;;;;;;;GAQG;AACH,qBAAa,6BAA8B,YAAW,uBAAuB;IAC3E,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;IAElD,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiBzD,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvC,OAAO,CAAC,aAAa;CAStB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAClC,KAAK,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACjC,8DAA8D;IAC9D,OAAO,CAAC,EAAE,uBAAuB,CAAC;CACnC;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkB;gBAE5B,IAAI,GAAE,kBAAuB;IAYzC;;;OAGG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAWrE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const d=1e4;class o{store=new Map;async increment(t,s){const e=Date.now(),i=this.store.get(t);return!i||e-i.windowStart>s?(!i&&this.store.size>=1e4&&this._evictExpired(e),this.store.set(t,{count:1,windowStart:e,windowMs:s}),1):(i.count+=1,i.count)}async reset(t){this.store.delete(t)}_evictExpired(t){for(const[s,e]of this.store)t-e.windowStart>e.windowMs&&this.store.delete(s)}}class a{backend;writes;reads;constructor(t={}){this.backend=t.backend??new o,this.writes={points:t.writes?.points??100,durationSeconds:t.writes?.durationSeconds??60},this.reads={points:t.reads?.points??500,durationSeconds:t.reads?.durationSeconds??60}}async check(t,s){const e=s==="write"?this.writes:this.reads,i=e.durationSeconds*1e3,n=await this.backend.increment(`${s}:${t}`,i);if(n>e.points)throw new Error(`Rate limit exceeded: ${n}/${e.points} ${s} requests in ${e.durationSeconds}s`)}}export{a as DndevRateLimiter,o as MemoryRateLimitStorageBackend};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const i=[/password\s*[:=]\s*\S+/gi,/secret\s*[:=]\s*\S+/gi,/api[_-]?key\s*[:=]\s*\S+/gi,/token\s*[:=]\s*\S+/gi,/bearer\s+[A-Za-z0-9\-._~+/]+=*/gi,/-----BEGIN .+?-----/g,/sk_live_[A-Za-z0-9]+/g,/sk_test_[A-Za-z0-9]+/g,/ghp_[A-Za-z0-9]{36,}/g,/gho_[A-Za-z0-9]{36,}/g,/AKIA[A-Z0-9]{16}/g,/xox[bpsa]-[A-Za-z0-9\-]+/g,/glpat-[A-Za-z0-9\-_]{20,}/g],n=/password|passwd|secret|token|apikey|api_key|credential|private_key|access_key|\bauth\b/i;function a(e){if(typeof e=="string"){let t=e;for(const r of i)t=t.replace(r,"[REDACTED]");return t}if(Array.isArray(e))return e.map(a);if(e!==null&&typeof e=="object"){const t={};for(const[r,s]of Object.entries(e))t[r]=n.test(r)?"[REDACTED]":a(s);return t}return e}function o(e,t){let r,s;try{s=JSON.stringify(e),r=JSON.stringify(a(e))}catch{throw new Error(`[dndev/security] assertNoSecrets: cannot serialize value in "${t}". Non-serializable values cannot be verified for secrets. Audit the object manually.`)}if(r!==s)throw new Error(`[dndev/security] Secret detected in ${t}. Aborting to prevent credential leak.`)}export{o as assertNoSecrets,a as scrubSecrets};
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { AuditLogger } from './AuditLogger';
|
|
2
2
|
export type { AuditLoggerOptions } from './AuditLogger';
|
|
3
|
-
export { DndevRateLimiter,
|
|
4
|
-
export type {
|
|
3
|
+
export { DndevRateLimiter, MemoryRateLimitStorageBackend } from './RateLimiter';
|
|
4
|
+
export type { RateLimitStorageBackend, RateLimiterOptions, RateLimitWindow } from './RateLimiter';
|
|
5
5
|
export { PiiEncryptor } from './PiiEncryptor';
|
|
6
6
|
export { AuthHardening } from './AuthHardening';
|
|
7
7
|
export type { AuthHardeningConfig, LockoutResult } from './AuthHardening';
|
|
@@ -12,5 +12,5 @@ export type { RetentionPolicy, ErasureRequest, ErasureResult } from './PrivacyMa
|
|
|
12
12
|
export { scrubSecrets, assertNoSecrets } from './SecretValidator';
|
|
13
13
|
export { DndevSecurity } from './DndevSecurity';
|
|
14
14
|
export type { DndevSecurityConfig } from './DndevSecurity';
|
|
15
|
-
export type { SecurityContext, AuditEvent, AuditEventType } from '../common/SecurityConfig';
|
|
15
|
+
export type { SecurityContext, AuditEvent, AuditEventType, RateLimitBackend, ServerRateLimitConfig, ServerRateLimitResult, AuthHardeningContext } from '../common/SecurityConfig';
|
|
16
16
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,EAAE,gBAAgB,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,EAAE,gBAAgB,EAAE,6BAA6B,EAAE,MAAM,eAAe,CAAC;AAChF,YAAY,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAElG,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE1E,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAExF,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEvF,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAElE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG3D,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC"}
|
package/dist/server/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AuditLogger as
|
|
1
|
+
import{AuditLogger as r}from"./AuditLogger";import{DndevRateLimiter as a,MemoryRateLimitStorageBackend as e}from"./RateLimiter";import{PiiEncryptor as t}from"./PiiEncryptor";import{AuthHardening as o}from"./AuthHardening";import{AnomalyDetector as s}from"./AnomalyDetector";import{PrivacyManager as i}from"./PrivacyManager";import{scrubSecrets as m,assertNoSecrets as c}from"./SecretValidator";import{DndevSecurity as n}from"./DndevSecurity";export{s as AnomalyDetector,r as AuditLogger,o as AuthHardening,a as DndevRateLimiter,n as DndevSecurity,e as MemoryRateLimitStorageBackend,t as PiiEncryptor,i as PrivacyManager,c as assertNoSecrets,m as scrubSecrets};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@donotdev/security",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
@@ -22,13 +22,13 @@
|
|
|
22
22
|
"scripts": {
|
|
23
23
|
"dev": "tsc --noEmit --watch --listFiles false --listEmittedFiles false",
|
|
24
24
|
"clean": "rimraf dist tsconfig.tsbuildinfo",
|
|
25
|
-
"type-check": "tsc --noEmit",
|
|
25
|
+
"type-check": "bunx tsc --noEmit",
|
|
26
26
|
"test": "vitest run",
|
|
27
27
|
"test:watch": "vitest"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {},
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"@donotdev/core": "^0.0.
|
|
31
|
+
"@donotdev/core": "^0.0.25"
|
|
32
32
|
},
|
|
33
33
|
"files": [
|
|
34
34
|
"dist",
|