@memberjunction/network-utils 0.0.0 → 6.1.0-edge.4
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/LICENSE +183 -0
- package/README.md +458 -27
- package/dist/HttpClient.d.ts +620 -0
- package/dist/HttpClient.d.ts.map +1 -0
- package/dist/HttpClient.js +670 -0
- package/dist/HttpClient.js.map +1 -0
- package/dist/SSRFGuard.d.ts +168 -0
- package/dist/SSRFGuard.d.ts.map +1 -0
- package/dist/SSRFGuard.js +408 -0
- package/dist/SSRFGuard.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpClient.js","sourceRoot":"","sources":["../src/HttpClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAqH3C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IAkBhC,YACI,OAAe,EACf,OASC;QAED,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;QAC3C,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;QACrC,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC;QAC5C,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,KAAK,CAAC;IACpD,CAAC;CACJ;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACtC,OAAO,KAAK,YAAY,SAAS,CAAC;AACtC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAc;IAC9C,IAAI,KAAK,YAAY,SAAS,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC,WAAW,CAAC;IAC7B,CAAC;IACD,OAAO,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC;AACjE,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAqC;IAClE,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IACrC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxC,SAAS;QACb,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACvB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACvB,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,YAAY,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;YACjF,CAAC;QACL,CAAC;aAAM,IAAI,KAAK,YAAY,IAAI,EAAE,CAAC;YAC/B,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACJ,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,KAAkC,CAAC,CAAC,CAAC;QACnE,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC7B,CAAC;AAED,0EAA0E;AAC1E,SAAS,UAAU,CAAC,MAAyB;IACzC,IAAI,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;IACrB,IAAI,MAAM,CAAC,OAAO,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;QACzF,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC;QACnD,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;IAC3B,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,EAAE,GAAG,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,EAAE,EAAE,CAAC;YACL,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QAChD,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED,sFAAsF;AACtF,SAAS,YAAY,CAAC,IAAa;IAC/B,OAAO,CACH,OAAO,IAAI,KAAK,QAAQ;QACxB,IAAI,YAAY,eAAe;QAC/B,IAAI,YAAY,WAAW;QAC3B,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC;QACxB,CAAC,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,YAAY,IAAI,CAAC;QACrD,CAAC,OAAO,QAAQ,KAAK,WAAW,IAAI,IAAI,YAAY,QAAQ,CAAC;QAC7D,CAAC,OAAO,cAAc,KAAK,WAAW,IAAI,IAAI,YAAY,cAAc,CAAC,CAC5E,CAAC;AACN,CAAC;AAED,uEAAuE;AACvE,SAAS,eAAe,CAAC,OAAgB;IACrC,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAC3B,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,GAAG,KAAK,CAAC;IACtC,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,uFAAuF;AACvF,KAAK,UAAU,QAAQ,CAAC,QAAkB,EAAE,YAA8B;IACtE,QAAQ,YAAY,EAAE,CAAC;QACnB,KAAK,MAAM;YACP,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC;QAChB,KAAK,QAAQ;YACT,OAAO,QAAQ,CAAC,IAAI,CAAC;QACzB,KAAK,aAAa;YACd,OAAO,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC;QACxC,KAAK,MAAM;YACP,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACjC,KAAK,MAAM;YACP,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACjC,KAAK,MAAM,CAAC;QACZ,OAAO,CAAC,CAAC,CAAC;YACN,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACpB,OAAO,IAAI,CAAC;YAChB,CAAC;YACD,IAAI,CAAC;gBACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACL,8EAA8E;gBAC9E,4EAA4E;gBAC5E,OAAO,IAAI,CAAC;YAChB,CAAC;QACL,CAAC;IACL,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAc,MAAyB;IACpE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,KAAK,CAAC;IACtC,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC;IACnD,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC;IACjD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,KAAK,CAAC;IACxC,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,IAAI,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,OAAO,GAA2B,EAAE,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;IAE9D,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACnB,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,eAAe,CAAC,CAAC;QAC5F,IAAI,CAAC,aAAa,EAAE,CAAC;YACjB,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACpH,OAAO,CAAC,eAAe,CAAC,GAAG,SAAS,OAAO,EAAE,CAAC;QAClD,CAAC;IACL,CAAC;IAED,IAAI,IAA0B,CAAC;IAC/B,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QAC7F,IAAI,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,IAAI,GAAG,MAAM,CAAC,IAAgB,CAAC;QACnC,CAAC;aAAM,CAAC;YACJ,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACnC,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,cAAc,CAAC,CAAC;YAC5F,IAAI,CAAC,cAAc,EAAE,CAAC;gBAClB,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;YACjD,CAAC;QACL,CAAC;IACL,CAAC;IAED,gFAAgF;IAChF,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACjF,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IAC/C,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAChB,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACxB,UAAU,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;aAAM,CAAC;YACJ,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3E,CAAC;IACL,CAAC;IAED,IAAI,CAAC;QACD,IAAI,QAAkB,CAAC;QACvB,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YACrB,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;gBAC5B,MAAM;gBACN,OAAO;gBACP,IAAI;gBACJ,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,YAAY,EAAE,YAAY;aAC7B,CAAC,CAAC;QACP,CAAC;aAAM,CAAC;YACJ,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBACxB,MAAM;gBACN,OAAO;gBACP,IAAI;gBACJ,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,QAAQ,EAAE,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ;aACnD,CAAC,CAAC;QACP,CAAC;QAED,MAAM,eAAe,GAAG,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC1D,4FAA4F;QAC5F,MAAM,IAAI,GAAG,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAE/E,MAAM,MAAM,GAAoB;YAC5B,IAAI,EAAE,IAAS;YACf,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;YAC/B,OAAO,EAAE,eAAe;YACxB,GAAG,EAAE,QAAQ,CAAC,GAAG,IAAI,GAAG;YACxB,EAAE,EAAE,QAAQ,CAAC,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG;SACtD,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,YAAY,EAAE,CAAC;YAC7B,MAAM,IAAI,SAAS,CAAC,mCAAmC,QAAQ,CAAC,MAAM,EAAE,EAAE;gBACtE,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;gBAC/B,IAAI,EAAE,IAAI;gBACV,OAAO,EAAE,eAAe;gBACxB,GAAG,EAAE,MAAM,CAAC,GAAG;gBACf,MAAM,EAAE,MAAM;aACjB,CAAC,CAAC;QACP,CAAC;QAED,OAAO,MAAM,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,IAAI,KAAK,YAAY,SAAS,EAAE,CAAC;YAC7B,MAAM,KAAK,CAAC;QAChB,CAAC;QACD,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC;QAC1C,MAAM,WAAW,GAAG,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;QAC/D,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,WAAW,CAAC;QAC1C,MAAM,OAAO,GAAG,SAAS;YACrB,CAAC,CAAC,cAAc,GAAG,oBAAoB,OAAO,IAAI;YAClD,CAAC,CAAC,WAAW;gBACX,CAAC,CAAC,cAAc,GAAG,8BAA8B;gBACjD,CAAC,CAAC,cAAc,GAAG,YAAY,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9F,yFAAyF;QACzF,+EAA+E;QAC/E,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACvD,MAAM,KAAK,CAAC;QAChB,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,CAAC;IAC/G,CAAC;YAAS,CAAC;QACP,IAAI,KAAK,EAAE,CAAC;YACR,YAAY,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;QACD,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAC/D,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAc,GAAW,EAAE,MAA2D;IAC/G,OAAO,MAAM,WAAW,CAAI,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AACxE,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAc,GAAW,EAAE,IAAc,EAAE,MAA2D;IAChI,OAAO,MAAM,WAAW,CAAI,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AACrF,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAc,GAAW,EAAE,IAAc,EAAE,MAA2D;IAC/H,OAAO,MAAM,WAAW,CAAI,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AACpF,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAc,GAAW,EAAE,IAAc,EAAE,MAA2D;IACjI,OAAO,MAAM,WAAW,CAAI,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AACtF,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAc,GAAW,EAAE,MAA2D;IAClH,OAAO,MAAM,WAAW,CAAI,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAc,GAAW,EAAE,MAA2D;IAChH,OAAO,MAAM,WAAW,CAAI,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;AAC/F,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAc,MAAyB;IACxE,OAAO,MAAM,WAAW,CAAI,EAAE,GAAG,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;AAClE,CAAC;AAsFD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,MAAM,OAAO,UAAU;IAGnB,YAAY,UAA6B,EAAE;QACvC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IAC5B,CAAC;IAED;;;OAGG;IACH,IAAW,OAAO;QACd,OAAO,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACI,KAAK,CAAC,OAAO,CAAc,MAAyB;QACvD,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,IAAI,CAAC,CAAC;QACjD,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,SAAS,CAAC;YACN,IAAI,MAAM,GAAsB;gBAC5B,GAAG,MAAM;gBACT,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO;gBAChD,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO;gBAChD,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW;gBAC5D,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY;gBAC/D,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS;gBACtD,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,OAAO,EAAE;aAC3D,CAAC;YAEF,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;gBAC1B,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACnD,CAAC;YAED,IAAI,CAAC;gBACD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAI,MAAM,CAAC,CAAC;gBAC9C,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;oBAC3B,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAiC,CAAC,CAAC;gBACtE,CAAC;gBACD,OAAO,QAAQ,CAAC;YACpB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACb,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,OAAO,IAAI,UAAU,EAAE,CAAC;oBACzE,MAAM,KAAK,CAAC;gBAChB,CAAC;gBACD,OAAO,EAAE,CAAC;gBACV,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;gBAChE,IAAI,CAAC,WAAW,EAAE,CAAC;oBACf,MAAM,KAAK,CAAC;gBAChB,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;IAED;;;;;;;;OAQG;IACI,KAAK,CAAC,GAAG,CAAc,GAAW,EAAE,MAA2D;QAClG,OAAO,MAAM,IAAI,CAAC,OAAO,CAAI,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACzE,CAAC;IAED;;;;;;;;;OASG;IACI,KAAK,CAAC,IAAI,CAAc,GAAW,EAAE,IAAc,EAAE,MAA2D;QACnH,OAAO,MAAM,IAAI,CAAC,OAAO,CAAI,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACtF,CAAC;IAED;;;;;;;;;OASG;IACI,KAAK,CAAC,GAAG,CAAc,GAAW,EAAE,IAAc,EAAE,MAA2D;QAClH,OAAO,MAAM,IAAI,CAAC,OAAO,CAAI,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACrF,CAAC;IAED;;;;;;;;;OASG;IACI,KAAK,CAAC,KAAK,CAAc,GAAW,EAAE,IAAc,EAAE,MAA2D;QACpH,OAAO,MAAM,IAAI,CAAC,OAAO,CAAI,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACvF,CAAC;IAED;;;;;;;;OAQG;IACI,KAAK,CAAC,MAAM,CAAc,GAAW,EAAE,MAA2D;QACrG,OAAO,MAAM,IAAI,CAAC,OAAO,CAAI,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED;;;;;;;;OAQG;IACI,KAAK,CAAC,IAAI,CAAc,GAAW,EAAE,MAA2D;QACnG,OAAO,MAAM,IAAI,CAAC,OAAO,CAAI,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;IAChG,CAAC;CACJ"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSRF (Server-Side Request Forgery) guard utilities.
|
|
3
|
+
*
|
|
4
|
+
* Any server-side code that fetches a caller-controlled URL is a read-SSRF risk: an attacker who can
|
|
5
|
+
* influence the URL (via an AI agent, an Action, a workflow, or an API parameter) could make the
|
|
6
|
+
* server request internal, loopback, link-local, or cloud-metadata endpoints (e.g.
|
|
7
|
+
* `http://169.254.169.254/` — the IMDS credentials endpoint) and read the response back. A scheme
|
|
8
|
+
* check alone does NOT prevent this, and DNS rebinding + HTTP redirects defeat any naive
|
|
9
|
+
* hostname-string check.
|
|
10
|
+
*
|
|
11
|
+
* This module resolves the hostname to ALL of its IP addresses and rejects the request if ANY of
|
|
12
|
+
* them fall in a private/reserved range, and re-validates every redirect hop. It has no third-party
|
|
13
|
+
* dependencies — only `node:dns` and `node:net` — which is why it lives in this low-level package
|
|
14
|
+
* rather than in any one consumer.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Thrown when a URL is rejected by the guard: malformed, a non-`http(s)` scheme, a hostname that
|
|
18
|
+
* does not resolve, or an address in a private/reserved range.
|
|
19
|
+
*
|
|
20
|
+
* Treat this as a security decision, not a transport failure. It is deliberately a distinct type
|
|
21
|
+
* from `HttpError` so a blocked URL is never retried, never counted as an outage, and can be
|
|
22
|
+
* surfaced to the caller as its own result code.
|
|
23
|
+
*
|
|
24
|
+
* The message is intentionally non-specific ("resolves to a private or reserved address") rather
|
|
25
|
+
* than naming the address it resolved to: echoing that back would turn the guard into an internal
|
|
26
|
+
* network scanner for whoever supplied the URL.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* try {
|
|
31
|
+
* const response = await SafeFetch(userSuppliedUrl);
|
|
32
|
+
* } catch (error) {
|
|
33
|
+
* if (error instanceof SSRFError) {
|
|
34
|
+
* return { Success: false, ResultCode: 'SSRF_BLOCKED', Message: error.message };
|
|
35
|
+
* }
|
|
36
|
+
* throw error;
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare class SSRFError extends Error {
|
|
41
|
+
constructor(message: string);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Classifies a single IP address literal as blocked or allowed.
|
|
45
|
+
*
|
|
46
|
+
* This is the pure, synchronous core of the guard — no DNS, no I/O — exposed for callers that have
|
|
47
|
+
* already resolved an address themselves (a proxy allowlist, a webhook source check, a test).
|
|
48
|
+
* For anything URL-shaped, use {@link AssertPublicUrl}, which also handles resolution and the
|
|
49
|
+
* scheme check.
|
|
50
|
+
*
|
|
51
|
+
* Fails closed: anything `net.isIP` does not recognize as a v4 or v6 literal is reported as
|
|
52
|
+
* blocked, so a parsing gap can never silently widen what is reachable.
|
|
53
|
+
*
|
|
54
|
+
* @param address - an IPv4 or IPv6 address literal (no brackets, no port).
|
|
55
|
+
* @returns true when the address falls in a blocked range and must not be fetched.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* IsBlockedIPAddress('169.254.169.254'); // true — cloud metadata endpoint
|
|
60
|
+
* IsBlockedIPAddress('10.0.0.5'); // true — RFC 1918 private
|
|
61
|
+
* IsBlockedIPAddress('::ffff:127.0.0.1'); // true — IPv4-mapped loopback
|
|
62
|
+
* IsBlockedIPAddress('93.184.216.34'); // false — public
|
|
63
|
+
* IsBlockedIPAddress('not-an-ip'); // true — fail closed
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function IsBlockedIPAddress(address: string): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Validates a URL for SSRF safety, resolving its hostname to check where it actually points.
|
|
69
|
+
*
|
|
70
|
+
* Four checks, in order — any one of them rejects:
|
|
71
|
+
* 1. The URL parses at all.
|
|
72
|
+
* 2. The scheme is `http` or `https`. This blocks `file://`, `gopher://`, `ftp://`, and the rest,
|
|
73
|
+
* which are otherwise a rich source of SSRF primitives.
|
|
74
|
+
* 3. The hostname resolves. A name that does not is rejected rather than handed to `fetch`.
|
|
75
|
+
* 4. EVERY address it resolves to is public. Literal-IP hosts — including bracketed IPv6 such as
|
|
76
|
+
* `[::1]` — are checked the same way.
|
|
77
|
+
*
|
|
78
|
+
* Checking every address, rather than the first, is what closes the multi-record bypass: an
|
|
79
|
+
* attacker controlling DNS can publish one public A record alongside `127.0.0.1` and rely on the
|
|
80
|
+
* resolver picking whichever it likes.
|
|
81
|
+
*
|
|
82
|
+
* IMPORTANT — validation alone is not protection. There is an unavoidable gap between this check
|
|
83
|
+
* and the connection that follows, during which DNS can change (a classic rebinding race). Prefer
|
|
84
|
+
* {@link SafeFetch}, which re-validates every redirect hop; see the package README's
|
|
85
|
+
* "What this does not protect against" section for the residual risk and how to close it.
|
|
86
|
+
*
|
|
87
|
+
* @param rawUrl - the caller-controlled URL to validate.
|
|
88
|
+
* @returns the parsed {@link URL}, ready to fetch.
|
|
89
|
+
* @throws {SSRFError} when the URL is malformed, uses an unsupported scheme, fails to resolve, or
|
|
90
|
+
* resolves to any private or reserved address.
|
|
91
|
+
*
|
|
92
|
+
* @example Validating without fetching
|
|
93
|
+
* ```ts
|
|
94
|
+
* // e.g. checking a batch of links before probing them
|
|
95
|
+
* for (const link of links) {
|
|
96
|
+
* try {
|
|
97
|
+
* await AssertPublicUrl(link.url);
|
|
98
|
+
* link.valid = true;
|
|
99
|
+
* } catch (error) {
|
|
100
|
+
* if (!(error instanceof SSRFError)) throw error;
|
|
101
|
+
* link.valid = false; // one bad URL must not fail the whole batch
|
|
102
|
+
* link.reason = error.message;
|
|
103
|
+
* }
|
|
104
|
+
* }
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export declare function AssertPublicUrl(rawUrl: string): Promise<URL>;
|
|
108
|
+
/**
|
|
109
|
+
* Everything the standard `fetch` init accepts, plus a redirect cap.
|
|
110
|
+
*
|
|
111
|
+
* `redirect` is deliberately not honored: {@link SafeFetch} always drives redirects manually so it
|
|
112
|
+
* can re-validate each hop, and silently accepting `redirect: 'follow'` would hand that back to the
|
|
113
|
+
* platform and defeat the guard.
|
|
114
|
+
*/
|
|
115
|
+
export type SafeFetchInit = RequestInit & {
|
|
116
|
+
/** Maximum number of redirect hops to follow (each re-validated). Default: 5. */
|
|
117
|
+
MaxRedirects?: number;
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* A drop-in replacement for `fetch` that is safe against SSRF. **This is the function to reach for**
|
|
121
|
+
* whenever the URL is not one you hard-coded.
|
|
122
|
+
*
|
|
123
|
+
* Two things make it safe where a one-time hostname check is not:
|
|
124
|
+
*
|
|
125
|
+
* 1. **Every hop is validated.** Automatic redirects are disabled (`redirect: 'manual'`) and each
|
|
126
|
+
* 3xx `Location` is resolved against the current URL and re-run through {@link AssertPublicUrl}
|
|
127
|
+
* before being followed. A public URL that 302s to `http://169.254.169.254/` is caught on the
|
|
128
|
+
* second hop, which is exactly what a naive check misses.
|
|
129
|
+
* 2. **Every address is checked**, not just the first — see {@link AssertPublicUrl}.
|
|
130
|
+
*
|
|
131
|
+
* Intermediate response bodies are cancelled as it goes, so following a chain does not leak
|
|
132
|
+
* sockets.
|
|
133
|
+
*
|
|
134
|
+
* @param rawUrl - the caller-controlled URL to fetch.
|
|
135
|
+
* @param init - standard `fetch` init, plus an optional `MaxRedirects` (default 5). Any `redirect`
|
|
136
|
+
* value is ignored; redirects are always driven manually.
|
|
137
|
+
* @returns the final {@link Response}, after following any redirects that passed validation. The
|
|
138
|
+
* body is unread, so the caller chooses `.json()`, `.text()`, `.arrayBuffer()`, and so on.
|
|
139
|
+
* @throws {SSRFError} when the initial URL — or any hop — is malformed, uses a non-http(s) scheme,
|
|
140
|
+
* fails to resolve, or resolves to a private or reserved address.
|
|
141
|
+
* @throws {Error} when the redirect limit is exceeded.
|
|
142
|
+
*
|
|
143
|
+
* @example Fetching an untrusted URL
|
|
144
|
+
* ```ts
|
|
145
|
+
* const response = await SafeFetch(userSuppliedUrl, {
|
|
146
|
+
* headers: { 'User-Agent': 'MemberJunction/1.0' },
|
|
147
|
+
* signal: AbortSignal.timeout(10000),
|
|
148
|
+
* MaxRedirects: 5,
|
|
149
|
+
* });
|
|
150
|
+
* if (!response.ok) return { Success: false, ResultCode: `HTTP_${response.status}` };
|
|
151
|
+
* const html = await response.text();
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* @example Reporting a block distinctly from a fetch failure
|
|
155
|
+
* ```ts
|
|
156
|
+
* try {
|
|
157
|
+
* return await SafeFetch(url);
|
|
158
|
+
* } catch (error) {
|
|
159
|
+
* if (error instanceof SSRFError) {
|
|
160
|
+
* // A security decision — do not retry, do not treat as an outage.
|
|
161
|
+
* return { Success: false, ResultCode: 'SSRF_BLOCKED' };
|
|
162
|
+
* }
|
|
163
|
+
* throw error;
|
|
164
|
+
* }
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
export declare function SafeFetch(rawUrl: string, init?: SafeFetchInit): Promise<Response>;
|
|
168
|
+
//# sourceMappingURL=SSRFGuard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SSRFGuard.d.ts","sourceRoot":"","sources":["../src/SSRFGuard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,SAAU,SAAQ,KAAK;gBACpB,OAAO,EAAE,MAAM;CAI9B;AAiKD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAY3D;AAUD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAyBlE;AAmCD;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG;IACtC,iFAAiF;IACjF,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,CAgCvF"}
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSRF (Server-Side Request Forgery) guard utilities.
|
|
3
|
+
*
|
|
4
|
+
* Any server-side code that fetches a caller-controlled URL is a read-SSRF risk: an attacker who can
|
|
5
|
+
* influence the URL (via an AI agent, an Action, a workflow, or an API parameter) could make the
|
|
6
|
+
* server request internal, loopback, link-local, or cloud-metadata endpoints (e.g.
|
|
7
|
+
* `http://169.254.169.254/` — the IMDS credentials endpoint) and read the response back. A scheme
|
|
8
|
+
* check alone does NOT prevent this, and DNS rebinding + HTTP redirects defeat any naive
|
|
9
|
+
* hostname-string check.
|
|
10
|
+
*
|
|
11
|
+
* This module resolves the hostname to ALL of its IP addresses and rejects the request if ANY of
|
|
12
|
+
* them fall in a private/reserved range, and re-validates every redirect hop. It has no third-party
|
|
13
|
+
* dependencies — only `node:dns` and `node:net` — which is why it lives in this low-level package
|
|
14
|
+
* rather than in any one consumer.
|
|
15
|
+
*/
|
|
16
|
+
import { promises as dns } from "node:dns";
|
|
17
|
+
import { isIP } from "node:net";
|
|
18
|
+
/**
|
|
19
|
+
* Thrown when a URL is rejected by the guard: malformed, a non-`http(s)` scheme, a hostname that
|
|
20
|
+
* does not resolve, or an address in a private/reserved range.
|
|
21
|
+
*
|
|
22
|
+
* Treat this as a security decision, not a transport failure. It is deliberately a distinct type
|
|
23
|
+
* from `HttpError` so a blocked URL is never retried, never counted as an outage, and can be
|
|
24
|
+
* surfaced to the caller as its own result code.
|
|
25
|
+
*
|
|
26
|
+
* The message is intentionally non-specific ("resolves to a private or reserved address") rather
|
|
27
|
+
* than naming the address it resolved to: echoing that back would turn the guard into an internal
|
|
28
|
+
* network scanner for whoever supplied the URL.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* try {
|
|
33
|
+
* const response = await SafeFetch(userSuppliedUrl);
|
|
34
|
+
* } catch (error) {
|
|
35
|
+
* if (error instanceof SSRFError) {
|
|
36
|
+
* return { Success: false, ResultCode: 'SSRF_BLOCKED', Message: error.message };
|
|
37
|
+
* }
|
|
38
|
+
* throw error;
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export class SSRFError extends Error {
|
|
43
|
+
constructor(message) {
|
|
44
|
+
super(message);
|
|
45
|
+
this.name = "SSRFError";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** Blocked IPv4 CIDR ranges, expressed as `[network, prefixLength]`. */
|
|
49
|
+
const BLOCKED_IPV4_CIDRS = [
|
|
50
|
+
["0.0.0.0", 8], // "this" network / unspecified
|
|
51
|
+
["10.0.0.0", 8], // private
|
|
52
|
+
["100.64.0.0", 10], // carrier-grade NAT
|
|
53
|
+
["127.0.0.0", 8], // loopback
|
|
54
|
+
["169.254.0.0", 16], // link-local (incl. 169.254.169.254 IMDS)
|
|
55
|
+
["172.16.0.0", 12], // private
|
|
56
|
+
["192.0.0.0", 24], // IETF protocol assignments
|
|
57
|
+
["192.0.2.0", 24], // TEST-NET-1 (documentation)
|
|
58
|
+
["192.88.99.0", 24], // 6to4 relay anycast
|
|
59
|
+
["192.168.0.0", 16], // private
|
|
60
|
+
["198.18.0.0", 15], // benchmarking
|
|
61
|
+
["198.51.100.0", 24], // TEST-NET-2 (documentation)
|
|
62
|
+
["203.0.113.0", 24], // TEST-NET-3 (documentation)
|
|
63
|
+
["224.0.0.0", 4], // multicast
|
|
64
|
+
["240.0.0.0", 4], // reserved (incl. 255.255.255.255 broadcast)
|
|
65
|
+
];
|
|
66
|
+
/**
|
|
67
|
+
* Parses a dotted-quad IPv4 string into an unsigned 32-bit integer.
|
|
68
|
+
* @returns the integer value, or `null` if the string is not a valid IPv4 address.
|
|
69
|
+
*/
|
|
70
|
+
function parseIPv4(ip) {
|
|
71
|
+
const octets = ip.split(".");
|
|
72
|
+
if (octets.length !== 4) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
let value = 0;
|
|
76
|
+
for (const octet of octets) {
|
|
77
|
+
if (!/^\d{1,3}$/.test(octet)) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const num = Number(octet);
|
|
81
|
+
if (num > 255) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
value = (value << 8) | num;
|
|
85
|
+
}
|
|
86
|
+
return value >>> 0;
|
|
87
|
+
}
|
|
88
|
+
/** Returns true if the given 32-bit IPv4 value falls within the `[network, prefix]` CIDR. */
|
|
89
|
+
function ipv4InCidr(value, network, prefix) {
|
|
90
|
+
const base = parseIPv4(network);
|
|
91
|
+
if (base === null) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
const mask = prefix === 0 ? 0 : (0xffffffff << (32 - prefix)) >>> 0;
|
|
95
|
+
return (value & mask) === (base & mask);
|
|
96
|
+
}
|
|
97
|
+
/** Returns true if an IPv4 address (as a 32-bit integer) is in any blocked range. */
|
|
98
|
+
function isBlockedIPv4Value(value) {
|
|
99
|
+
return BLOCKED_IPV4_CIDRS.some(([network, prefix]) => ipv4InCidr(value, network, prefix));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Expands an IPv6 string (already validated by `net.isIP`, so shortened `::` forms and embedded
|
|
103
|
+
* IPv4 tails are accepted) into its eight 16-bit groups.
|
|
104
|
+
* @returns the 8-element group array, or `null` if it cannot be parsed.
|
|
105
|
+
*/
|
|
106
|
+
function parseIPv6(ip) {
|
|
107
|
+
let addr = ip;
|
|
108
|
+
const zoneIndex = addr.indexOf("%");
|
|
109
|
+
if (zoneIndex !== -1) {
|
|
110
|
+
addr = addr.slice(0, zoneIndex);
|
|
111
|
+
}
|
|
112
|
+
const halves = addr.split("::");
|
|
113
|
+
if (halves.length > 2) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
const head = parseIPv6Groups(halves[0]);
|
|
117
|
+
if (head === null) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
if (halves.length === 1) {
|
|
121
|
+
return head.length === 8 ? head : null;
|
|
122
|
+
}
|
|
123
|
+
const tail = parseIPv6Groups(halves[1]);
|
|
124
|
+
if (tail === null) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
const missing = 8 - head.length - tail.length;
|
|
128
|
+
if (missing < 0) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
return [...head, ...new Array(missing).fill(0), ...tail];
|
|
132
|
+
}
|
|
133
|
+
/** Parses one side of an IPv6 address (the part before or after `::`) into 16-bit groups. */
|
|
134
|
+
function parseIPv6Groups(part) {
|
|
135
|
+
if (part === "") {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
const tokens = part.split(":");
|
|
139
|
+
const groups = [];
|
|
140
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
141
|
+
const token = tokens[i];
|
|
142
|
+
if (token.includes(".")) {
|
|
143
|
+
// Embedded IPv4 tail (e.g. ::ffff:192.168.0.1) — must be the final token.
|
|
144
|
+
if (i !== tokens.length - 1) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
const v4 = parseIPv4(token);
|
|
148
|
+
if (v4 === null) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
groups.push((v4 >>> 16) & 0xffff, v4 & 0xffff);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
if (!/^[0-9a-fA-F]{1,4}$/.test(token)) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
groups.push(parseInt(token, 16));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return groups;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Determines whether an IPv6 address (given as its 8 groups) is in a blocked range: loopback (`::1`),
|
|
164
|
+
* unspecified (`::`), ULA (`fc00::/7`), link-local (`fe80::/10`), multicast (`ff00::/8`), or an
|
|
165
|
+
* IPv4-mapped/compatible address whose embedded IPv4 is itself blocked (`::ffff:a.b.c.d`, `::a.b.c.d`).
|
|
166
|
+
*/
|
|
167
|
+
function isBlockedIPv6Groups(groups) {
|
|
168
|
+
const isUnspecified = groups.every((g) => g === 0);
|
|
169
|
+
if (isUnspecified) {
|
|
170
|
+
return true; // ::
|
|
171
|
+
}
|
|
172
|
+
const isLoopback = groups.slice(0, 7).every((g) => g === 0) && groups[7] === 1;
|
|
173
|
+
if (isLoopback) {
|
|
174
|
+
return true; // ::1
|
|
175
|
+
}
|
|
176
|
+
// IPv4-mapped (::ffff:0:0/96) and IPv4-compatible (::/96) — unwrap and apply IPv4 rules.
|
|
177
|
+
const firstFiveZero = groups.slice(0, 5).every((g) => g === 0);
|
|
178
|
+
if (firstFiveZero && (groups[5] === 0xffff || groups[5] === 0)) {
|
|
179
|
+
const embedded = (((groups[6] << 16) >>> 0) | groups[7]) >>> 0;
|
|
180
|
+
if (isBlockedIPv4Value(embedded)) {
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if ((groups[0] & 0xfe00) === 0xfc00) {
|
|
185
|
+
return true; // fc00::/7 (unique local address)
|
|
186
|
+
}
|
|
187
|
+
if ((groups[0] & 0xffc0) === 0xfe80) {
|
|
188
|
+
return true; // fe80::/10 (link-local)
|
|
189
|
+
}
|
|
190
|
+
if ((groups[0] & 0xff00) === 0xff00) {
|
|
191
|
+
return true; // ff00::/8 (multicast)
|
|
192
|
+
}
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Classifies a single IP address literal as blocked or allowed.
|
|
197
|
+
*
|
|
198
|
+
* This is the pure, synchronous core of the guard — no DNS, no I/O — exposed for callers that have
|
|
199
|
+
* already resolved an address themselves (a proxy allowlist, a webhook source check, a test).
|
|
200
|
+
* For anything URL-shaped, use {@link AssertPublicUrl}, which also handles resolution and the
|
|
201
|
+
* scheme check.
|
|
202
|
+
*
|
|
203
|
+
* Fails closed: anything `net.isIP` does not recognize as a v4 or v6 literal is reported as
|
|
204
|
+
* blocked, so a parsing gap can never silently widen what is reachable.
|
|
205
|
+
*
|
|
206
|
+
* @param address - an IPv4 or IPv6 address literal (no brackets, no port).
|
|
207
|
+
* @returns true when the address falls in a blocked range and must not be fetched.
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```ts
|
|
211
|
+
* IsBlockedIPAddress('169.254.169.254'); // true — cloud metadata endpoint
|
|
212
|
+
* IsBlockedIPAddress('10.0.0.5'); // true — RFC 1918 private
|
|
213
|
+
* IsBlockedIPAddress('::ffff:127.0.0.1'); // true — IPv4-mapped loopback
|
|
214
|
+
* IsBlockedIPAddress('93.184.216.34'); // false — public
|
|
215
|
+
* IsBlockedIPAddress('not-an-ip'); // true — fail closed
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
export function IsBlockedIPAddress(address) {
|
|
219
|
+
const family = isIP(address);
|
|
220
|
+
if (family === 4) {
|
|
221
|
+
const value = parseIPv4(address);
|
|
222
|
+
return value === null ? true : isBlockedIPv4Value(value);
|
|
223
|
+
}
|
|
224
|
+
if (family === 6) {
|
|
225
|
+
const groups = parseIPv6(address);
|
|
226
|
+
return groups === null ? true : isBlockedIPv6Groups(groups);
|
|
227
|
+
}
|
|
228
|
+
// Not a recognizable IP literal — fail closed.
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
/** Strips the surrounding brackets from an IPv6 literal hostname (e.g. `[::1]` -> `::1`). */
|
|
232
|
+
function stripIPv6Brackets(hostname) {
|
|
233
|
+
if (hostname.startsWith("[") && hostname.endsWith("]")) {
|
|
234
|
+
return hostname.slice(1, -1);
|
|
235
|
+
}
|
|
236
|
+
return hostname;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Validates a URL for SSRF safety, resolving its hostname to check where it actually points.
|
|
240
|
+
*
|
|
241
|
+
* Four checks, in order — any one of them rejects:
|
|
242
|
+
* 1. The URL parses at all.
|
|
243
|
+
* 2. The scheme is `http` or `https`. This blocks `file://`, `gopher://`, `ftp://`, and the rest,
|
|
244
|
+
* which are otherwise a rich source of SSRF primitives.
|
|
245
|
+
* 3. The hostname resolves. A name that does not is rejected rather than handed to `fetch`.
|
|
246
|
+
* 4. EVERY address it resolves to is public. Literal-IP hosts — including bracketed IPv6 such as
|
|
247
|
+
* `[::1]` — are checked the same way.
|
|
248
|
+
*
|
|
249
|
+
* Checking every address, rather than the first, is what closes the multi-record bypass: an
|
|
250
|
+
* attacker controlling DNS can publish one public A record alongside `127.0.0.1` and rely on the
|
|
251
|
+
* resolver picking whichever it likes.
|
|
252
|
+
*
|
|
253
|
+
* IMPORTANT — validation alone is not protection. There is an unavoidable gap between this check
|
|
254
|
+
* and the connection that follows, during which DNS can change (a classic rebinding race). Prefer
|
|
255
|
+
* {@link SafeFetch}, which re-validates every redirect hop; see the package README's
|
|
256
|
+
* "What this does not protect against" section for the residual risk and how to close it.
|
|
257
|
+
*
|
|
258
|
+
* @param rawUrl - the caller-controlled URL to validate.
|
|
259
|
+
* @returns the parsed {@link URL}, ready to fetch.
|
|
260
|
+
* @throws {SSRFError} when the URL is malformed, uses an unsupported scheme, fails to resolve, or
|
|
261
|
+
* resolves to any private or reserved address.
|
|
262
|
+
*
|
|
263
|
+
* @example Validating without fetching
|
|
264
|
+
* ```ts
|
|
265
|
+
* // e.g. checking a batch of links before probing them
|
|
266
|
+
* for (const link of links) {
|
|
267
|
+
* try {
|
|
268
|
+
* await AssertPublicUrl(link.url);
|
|
269
|
+
* link.valid = true;
|
|
270
|
+
* } catch (error) {
|
|
271
|
+
* if (!(error instanceof SSRFError)) throw error;
|
|
272
|
+
* link.valid = false; // one bad URL must not fail the whole batch
|
|
273
|
+
* link.reason = error.message;
|
|
274
|
+
* }
|
|
275
|
+
* }
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
export async function AssertPublicUrl(rawUrl) {
|
|
279
|
+
let parsed;
|
|
280
|
+
try {
|
|
281
|
+
parsed = new URL(rawUrl);
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
throw new SSRFError(`Invalid URL: ${rawUrl}`);
|
|
285
|
+
}
|
|
286
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
287
|
+
throw new SSRFError(`Unsupported URL scheme '${parsed.protocol}' — only http and https are allowed`);
|
|
288
|
+
}
|
|
289
|
+
const hostname = stripIPv6Brackets(parsed.hostname);
|
|
290
|
+
if (!hostname) {
|
|
291
|
+
throw new SSRFError("URL has no hostname");
|
|
292
|
+
}
|
|
293
|
+
const addresses = await resolveAllAddresses(hostname);
|
|
294
|
+
for (const address of addresses) {
|
|
295
|
+
if (IsBlockedIPAddress(address)) {
|
|
296
|
+
throw new SSRFError("URL resolves to a private or reserved address and was blocked");
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return parsed;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Resolves a hostname to every IP address it maps to.
|
|
303
|
+
*
|
|
304
|
+
* Uses `dns.lookup(host, { all: true })` rather than `dns.resolve4`/`resolve6` so the answer
|
|
305
|
+
* matches what the OS resolver — and therefore `fetch` — will actually use, including `/etc/hosts`
|
|
306
|
+
* entries and any local resolver policy. Literal IPs short-circuit to themselves.
|
|
307
|
+
*
|
|
308
|
+
* @param hostname - the host to resolve (IPv6 literals already unbracketed).
|
|
309
|
+
* @returns every address the hostname maps to; never empty.
|
|
310
|
+
* @throws {SSRFError} when the hostname cannot be resolved — failing closed rather than handing an
|
|
311
|
+
* unverified name to `fetch`.
|
|
312
|
+
*/
|
|
313
|
+
async function resolveAllAddresses(hostname) {
|
|
314
|
+
try {
|
|
315
|
+
const records = await dns.lookup(hostname, { all: true });
|
|
316
|
+
if (records.length === 0) {
|
|
317
|
+
throw new SSRFError(`Hostname '${hostname}' did not resolve to any address`);
|
|
318
|
+
}
|
|
319
|
+
return records.map((record) => record.address);
|
|
320
|
+
}
|
|
321
|
+
catch (error) {
|
|
322
|
+
if (error instanceof SSRFError) {
|
|
323
|
+
throw error;
|
|
324
|
+
}
|
|
325
|
+
throw new SSRFError(`Unable to resolve hostname '${hostname}': ${error instanceof Error ? error.message : String(error)}`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Status codes that carry a `Location` header worth following. 3xx codes absent from this set
|
|
330
|
+
* (300 Multiple Choices, 304 Not Modified, 305 Use Proxy) are returned to the caller as-is.
|
|
331
|
+
*/
|
|
332
|
+
const REDIRECT_STATUS_CODES = new Set([301, 302, 303, 307, 308]);
|
|
333
|
+
/**
|
|
334
|
+
* A drop-in replacement for `fetch` that is safe against SSRF. **This is the function to reach for**
|
|
335
|
+
* whenever the URL is not one you hard-coded.
|
|
336
|
+
*
|
|
337
|
+
* Two things make it safe where a one-time hostname check is not:
|
|
338
|
+
*
|
|
339
|
+
* 1. **Every hop is validated.** Automatic redirects are disabled (`redirect: 'manual'`) and each
|
|
340
|
+
* 3xx `Location` is resolved against the current URL and re-run through {@link AssertPublicUrl}
|
|
341
|
+
* before being followed. A public URL that 302s to `http://169.254.169.254/` is caught on the
|
|
342
|
+
* second hop, which is exactly what a naive check misses.
|
|
343
|
+
* 2. **Every address is checked**, not just the first — see {@link AssertPublicUrl}.
|
|
344
|
+
*
|
|
345
|
+
* Intermediate response bodies are cancelled as it goes, so following a chain does not leak
|
|
346
|
+
* sockets.
|
|
347
|
+
*
|
|
348
|
+
* @param rawUrl - the caller-controlled URL to fetch.
|
|
349
|
+
* @param init - standard `fetch` init, plus an optional `MaxRedirects` (default 5). Any `redirect`
|
|
350
|
+
* value is ignored; redirects are always driven manually.
|
|
351
|
+
* @returns the final {@link Response}, after following any redirects that passed validation. The
|
|
352
|
+
* body is unread, so the caller chooses `.json()`, `.text()`, `.arrayBuffer()`, and so on.
|
|
353
|
+
* @throws {SSRFError} when the initial URL — or any hop — is malformed, uses a non-http(s) scheme,
|
|
354
|
+
* fails to resolve, or resolves to a private or reserved address.
|
|
355
|
+
* @throws {Error} when the redirect limit is exceeded.
|
|
356
|
+
*
|
|
357
|
+
* @example Fetching an untrusted URL
|
|
358
|
+
* ```ts
|
|
359
|
+
* const response = await SafeFetch(userSuppliedUrl, {
|
|
360
|
+
* headers: { 'User-Agent': 'MemberJunction/1.0' },
|
|
361
|
+
* signal: AbortSignal.timeout(10000),
|
|
362
|
+
* MaxRedirects: 5,
|
|
363
|
+
* });
|
|
364
|
+
* if (!response.ok) return { Success: false, ResultCode: `HTTP_${response.status}` };
|
|
365
|
+
* const html = await response.text();
|
|
366
|
+
* ```
|
|
367
|
+
*
|
|
368
|
+
* @example Reporting a block distinctly from a fetch failure
|
|
369
|
+
* ```ts
|
|
370
|
+
* try {
|
|
371
|
+
* return await SafeFetch(url);
|
|
372
|
+
* } catch (error) {
|
|
373
|
+
* if (error instanceof SSRFError) {
|
|
374
|
+
* // A security decision — do not retry, do not treat as an outage.
|
|
375
|
+
* return { Success: false, ResultCode: 'SSRF_BLOCKED' };
|
|
376
|
+
* }
|
|
377
|
+
* throw error;
|
|
378
|
+
* }
|
|
379
|
+
* ```
|
|
380
|
+
*/
|
|
381
|
+
export async function SafeFetch(rawUrl, init) {
|
|
382
|
+
const maxRedirects = init?.MaxRedirects ?? 5;
|
|
383
|
+
const { MaxRedirects: _ignored, ...fetchInit } = init ?? {};
|
|
384
|
+
let currentUrl = rawUrl;
|
|
385
|
+
let redirectCount = 0;
|
|
386
|
+
// eslint-disable-next-line no-constant-condition
|
|
387
|
+
while (true) {
|
|
388
|
+
const validated = await AssertPublicUrl(currentUrl);
|
|
389
|
+
const response = await fetch(validated.href, { ...fetchInit, redirect: "manual" });
|
|
390
|
+
if (!REDIRECT_STATUS_CODES.has(response.status)) {
|
|
391
|
+
return response;
|
|
392
|
+
}
|
|
393
|
+
const location = response.headers.get("location");
|
|
394
|
+
if (!location) {
|
|
395
|
+
// A redirect status with no Location header — nothing to follow; hand it back.
|
|
396
|
+
return response;
|
|
397
|
+
}
|
|
398
|
+
if (redirectCount >= maxRedirects) {
|
|
399
|
+
void response.body?.cancel();
|
|
400
|
+
throw new Error(`Exceeded maximum of ${maxRedirects} redirects while fetching ${rawUrl}`);
|
|
401
|
+
}
|
|
402
|
+
// Release the intermediate response body before following the next hop.
|
|
403
|
+
void response.body?.cancel();
|
|
404
|
+
redirectCount++;
|
|
405
|
+
currentUrl = new URL(location, validated).href;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
//# sourceMappingURL=SSRFGuard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SSRFGuard.js","sourceRoot":"","sources":["../src/SSRFGuard.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@memberjunction/network-utils` — low-level, server-side network utilities.
|
|
3
|
+
*
|
|
4
|
+
* Two things live here, and they belong together:
|
|
5
|
+
*
|
|
6
|
+
* 1. **{@link SafeFetch} / {@link AssertPublicUrl}** — the SSRF guard. Any code that fetches a
|
|
7
|
+
* caller-controlled URL needs it, and that is not an Actions-specific concern, so it sits in a
|
|
8
|
+
* package anything server-side can depend on.
|
|
9
|
+
* 2. **{@link HttpClient} / {@link HttpRequest}** — a native-`fetch` HTTP client that replaces
|
|
10
|
+
* `axios` across the repo. Having one client means the SSRF guard is one option flag away
|
|
11
|
+
* (`ValidateUrl`) at every call site, instead of something each package has to remember to build.
|
|
12
|
+
*
|
|
13
|
+
* NODE ONLY. This package imports `node:dns` and `node:net` and must never be pulled into a browser
|
|
14
|
+
* bundle — which is exactly why the guard does not live in `@memberjunction/global`.
|
|
15
|
+
*/
|
|
16
|
+
export * from "./SSRFGuard.js";
|
|
17
|
+
export * from "./HttpClient.js";
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@memberjunction/network-utils` — low-level, server-side network utilities.
|
|
3
|
+
*
|
|
4
|
+
* Two things live here, and they belong together:
|
|
5
|
+
*
|
|
6
|
+
* 1. **{@link SafeFetch} / {@link AssertPublicUrl}** — the SSRF guard. Any code that fetches a
|
|
7
|
+
* caller-controlled URL needs it, and that is not an Actions-specific concern, so it sits in a
|
|
8
|
+
* package anything server-side can depend on.
|
|
9
|
+
* 2. **{@link HttpClient} / {@link HttpRequest}** — a native-`fetch` HTTP client that replaces
|
|
10
|
+
* `axios` across the repo. Having one client means the SSRF guard is one option flag away
|
|
11
|
+
* (`ValidateUrl`) at every call site, instead of something each package has to remember to build.
|
|
12
|
+
*
|
|
13
|
+
* NODE ONLY. This package imports `node:dns` and `node:net` and must never be pulled into a browser
|
|
14
|
+
* bundle — which is exactly why the guard does not live in `@memberjunction/global`.
|
|
15
|
+
*/
|
|
16
|
+
export * from "./SSRFGuard.js";
|
|
17
|
+
export * from "./HttpClient.js";
|
|
18
|
+
//# sourceMappingURL=index.js.map
|