eslint-plugin-jwt-security 3.5.1 → 3.5.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-jwt-security",
3
- "version": "3.5.1",
3
+ "version": "3.5.3",
4
4
  "description": "ESLint plugin for JWT security — detects algorithm confusion (CVE-2022-23540), alg:none, weak or hardcoded secrets, and decode-without-verify.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -79,7 +79,7 @@
79
79
  "node": ">=18.0.0"
80
80
  },
81
81
  "dependencies": {
82
- "@interlace/eslint-devkit": "^1.19.0"
82
+ "@interlace/eslint-devkit": "^1.20.2"
83
83
  },
84
84
  "peerDependencies": {
85
85
  "eslint": "^8.40.0 || ^9.0.0 || ^10.0.0",
package/src/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noSensitivePayload=exports.requireMaxAge=exports.noTimestampManipulation=exports.requireAudienceValidation=exports.requireIssuerValidation=exports.requireIssuedAt=exports.noHardcodedSecret=exports.requireExpiration=exports.noWeakSecret=exports.noDecodeWithoutVerify=exports.requireAlgorithmWhitelist=exports.noAlgorithmConfusion=exports.noAlgorithmNone=exports.configs=exports.plugin=exports.rules=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const no_algorithm_none_1=require("./rules/no-algorithm-none");Object.defineProperty(exports,"noAlgorithmNone",{enumerable:true,get:function(){return no_algorithm_none_1.noAlgorithmNone}});const no_algorithm_confusion_1=require("./rules/no-algorithm-confusion");Object.defineProperty(exports,"noAlgorithmConfusion",{enumerable:true,get:function(){return no_algorithm_confusion_1.noAlgorithmConfusion}});const require_algorithm_whitelist_1=require("./rules/require-algorithm-whitelist");Object.defineProperty(exports,"requireAlgorithmWhitelist",{enumerable:true,get:function(){return require_algorithm_whitelist_1.requireAlgorithmWhitelist}});const no_decode_without_verify_1=require("./rules/no-decode-without-verify");Object.defineProperty(exports,"noDecodeWithoutVerify",{enumerable:true,get:function(){return no_decode_without_verify_1.noDecodeWithoutVerify}});const no_weak_secret_1=require("./rules/no-weak-secret");Object.defineProperty(exports,"noWeakSecret",{enumerable:true,get:function(){return no_weak_secret_1.noWeakSecret}});const require_expiration_1=require("./rules/require-expiration");Object.defineProperty(exports,"requireExpiration",{enumerable:true,get:function(){return require_expiration_1.requireExpiration}});const no_hardcoded_secret_1=require("./rules/no-hardcoded-secret");Object.defineProperty(exports,"noHardcodedSecret",{enumerable:true,get:function(){return no_hardcoded_secret_1.noHardcodedSecret}});const require_issued_at_1=require("./rules/require-issued-at");Object.defineProperty(exports,"requireIssuedAt",{enumerable:true,get:function(){return require_issued_at_1.requireIssuedAt}});const require_issuer_validation_1=require("./rules/require-issuer-validation");Object.defineProperty(exports,"requireIssuerValidation",{enumerable:true,get:function(){return require_issuer_validation_1.requireIssuerValidation}});const require_audience_validation_1=require("./rules/require-audience-validation");Object.defineProperty(exports,"requireAudienceValidation",{enumerable:true,get:function(){return require_audience_validation_1.requireAudienceValidation}});const no_timestamp_manipulation_1=require("./rules/no-timestamp-manipulation");Object.defineProperty(exports,"noTimestampManipulation",{enumerable:true,get:function(){return no_timestamp_manipulation_1.noTimestampManipulation}});const require_max_age_1=require("./rules/require-max-age");Object.defineProperty(exports,"requireMaxAge",{enumerable:true,get:function(){return require_max_age_1.requireMaxAge}});const no_sensitive_payload_1=require("./rules/no-sensitive-payload");Object.defineProperty(exports,"noSensitivePayload",{enumerable:true,get:function(){return no_sensitive_payload_1.noSensitivePayload}});exports.rules={get"no-algorithm-none"(){return require("./rules/no-algorithm-none").noAlgorithmNone},get"no-algorithm-confusion"(){return require("./rules/no-algorithm-confusion").noAlgorithmConfusion},get"require-algorithm-whitelist"(){return require("./rules/require-algorithm-whitelist").requireAlgorithmWhitelist},get"no-decode-without-verify"(){return require("./rules/no-decode-without-verify").noDecodeWithoutVerify},get"no-weak-secret"(){return require("./rules/no-weak-secret").noWeakSecret},get"require-expiration"(){return require("./rules/require-expiration").requireExpiration},get"no-hardcoded-secret"(){return require("./rules/no-hardcoded-secret").noHardcodedSecret},get"require-issued-at"(){return require("./rules/require-issued-at").requireIssuedAt},get"require-issuer-validation"(){return require("./rules/require-issuer-validation").requireIssuerValidation},get"require-audience-validation"(){return require("./rules/require-audience-validation").requireAudienceValidation},get"no-timestamp-manipulation"(){return require("./rules/no-timestamp-manipulation").noTimestampManipulation},get"require-max-age"(){return require("./rules/require-max-age").requireMaxAge},get"no-sensitive-payload"(){return require("./rules/no-sensitive-payload").noSensitivePayload}};(0,eslint_devkit_1.withCanonicalDocsUrls)("plugin-jwt-security",exports.rules);exports.plugin={meta:{name:"eslint-plugin-jwt-security",version:"3.5.1"},rules:exports.rules};const recommendedRules={"jwt-security/no-algorithm-none":"error","jwt-security/no-algorithm-confusion":"error","jwt-security/require-algorithm-whitelist":"error","jwt-security/no-decode-without-verify":"error","jwt-security/no-weak-secret":"error","jwt-security/no-hardcoded-secret":"error","jwt-security/no-timestamp-manipulation":"error","jwt-security/require-expiration":"error","jwt-security/no-sensitive-payload":"warn","jwt-security/require-issued-at":"warn"};const strictRules={"jwt-security/no-algorithm-none":"error","jwt-security/no-algorithm-confusion":"error","jwt-security/require-algorithm-whitelist":"error","jwt-security/no-decode-without-verify":"error","jwt-security/no-weak-secret":"error","jwt-security/no-hardcoded-secret":"error","jwt-security/require-expiration":"error","jwt-security/require-issued-at":"error","jwt-security/require-issuer-validation":"error","jwt-security/require-audience-validation":"error","jwt-security/no-timestamp-manipulation":"error","jwt-security/require-max-age":"error","jwt-security/no-sensitive-payload":"error"};const legacyRules={"jwt-security/no-algorithm-none":"error","jwt-security/no-algorithm-confusion":"error","jwt-security/no-hardcoded-secret":"warn"};exports.configs={flagship:{plugins:{"jwt-security":exports.plugin,jwt:exports.plugin},rules:{"jwt-security/no-algorithm-none":"error"}},recommended:{plugins:{"jwt-security":exports.plugin,jwt:exports.plugin},rules:recommendedRules},strict:{plugins:{"jwt-security":exports.plugin,jwt:exports.plugin},rules:strictRules},legacy:{plugins:{"jwt-security":exports.plugin,jwt:exports.plugin},rules:legacyRules},all:{plugins:{"jwt-security":exports.plugin,jwt:exports.plugin},rules:strictRules}};exports.default=exports.plugin;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noSensitivePayload=exports.requireMaxAge=exports.noTimestampManipulation=exports.requireAudienceValidation=exports.requireIssuerValidation=exports.requireIssuedAt=exports.noHardcodedSecret=exports.requireExpiration=exports.noWeakSecret=exports.noDecodeWithoutVerify=exports.requireAlgorithmWhitelist=exports.noAlgorithmConfusion=exports.noAlgorithmNone=exports.configs=exports.plugin=exports.rules=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const no_algorithm_none_1=require("./rules/no-algorithm-none");Object.defineProperty(exports,"noAlgorithmNone",{enumerable:true,get:function(){return no_algorithm_none_1.noAlgorithmNone}});const no_algorithm_confusion_1=require("./rules/no-algorithm-confusion");Object.defineProperty(exports,"noAlgorithmConfusion",{enumerable:true,get:function(){return no_algorithm_confusion_1.noAlgorithmConfusion}});const require_algorithm_whitelist_1=require("./rules/require-algorithm-whitelist");Object.defineProperty(exports,"requireAlgorithmWhitelist",{enumerable:true,get:function(){return require_algorithm_whitelist_1.requireAlgorithmWhitelist}});const no_decode_without_verify_1=require("./rules/no-decode-without-verify");Object.defineProperty(exports,"noDecodeWithoutVerify",{enumerable:true,get:function(){return no_decode_without_verify_1.noDecodeWithoutVerify}});const no_weak_secret_1=require("./rules/no-weak-secret");Object.defineProperty(exports,"noWeakSecret",{enumerable:true,get:function(){return no_weak_secret_1.noWeakSecret}});const require_expiration_1=require("./rules/require-expiration");Object.defineProperty(exports,"requireExpiration",{enumerable:true,get:function(){return require_expiration_1.requireExpiration}});const no_hardcoded_secret_1=require("./rules/no-hardcoded-secret");Object.defineProperty(exports,"noHardcodedSecret",{enumerable:true,get:function(){return no_hardcoded_secret_1.noHardcodedSecret}});const require_issued_at_1=require("./rules/require-issued-at");Object.defineProperty(exports,"requireIssuedAt",{enumerable:true,get:function(){return require_issued_at_1.requireIssuedAt}});const require_issuer_validation_1=require("./rules/require-issuer-validation");Object.defineProperty(exports,"requireIssuerValidation",{enumerable:true,get:function(){return require_issuer_validation_1.requireIssuerValidation}});const require_audience_validation_1=require("./rules/require-audience-validation");Object.defineProperty(exports,"requireAudienceValidation",{enumerable:true,get:function(){return require_audience_validation_1.requireAudienceValidation}});const no_timestamp_manipulation_1=require("./rules/no-timestamp-manipulation");Object.defineProperty(exports,"noTimestampManipulation",{enumerable:true,get:function(){return no_timestamp_manipulation_1.noTimestampManipulation}});const require_max_age_1=require("./rules/require-max-age");Object.defineProperty(exports,"requireMaxAge",{enumerable:true,get:function(){return require_max_age_1.requireMaxAge}});const no_sensitive_payload_1=require("./rules/no-sensitive-payload");Object.defineProperty(exports,"noSensitivePayload",{enumerable:true,get:function(){return no_sensitive_payload_1.noSensitivePayload}});exports.rules={get"no-algorithm-none"(){return require("./rules/no-algorithm-none").noAlgorithmNone},get"no-algorithm-confusion"(){return require("./rules/no-algorithm-confusion").noAlgorithmConfusion},get"require-algorithm-whitelist"(){return require("./rules/require-algorithm-whitelist").requireAlgorithmWhitelist},get"no-decode-without-verify"(){return require("./rules/no-decode-without-verify").noDecodeWithoutVerify},get"no-weak-secret"(){return require("./rules/no-weak-secret").noWeakSecret},get"require-expiration"(){return require("./rules/require-expiration").requireExpiration},get"no-hardcoded-secret"(){return require("./rules/no-hardcoded-secret").noHardcodedSecret},get"require-issued-at"(){return require("./rules/require-issued-at").requireIssuedAt},get"require-issuer-validation"(){return require("./rules/require-issuer-validation").requireIssuerValidation},get"require-audience-validation"(){return require("./rules/require-audience-validation").requireAudienceValidation},get"no-timestamp-manipulation"(){return require("./rules/no-timestamp-manipulation").noTimestampManipulation},get"require-max-age"(){return require("./rules/require-max-age").requireMaxAge},get"no-sensitive-payload"(){return require("./rules/no-sensitive-payload").noSensitivePayload}};(0,eslint_devkit_1.withCanonicalDocsUrls)("plugin-jwt-security",exports.rules);exports.plugin={meta:{name:"eslint-plugin-jwt-security",version:"3.5.3"},rules:exports.rules};const recommendedRules={"jwt-security/no-algorithm-none":"error","jwt-security/no-algorithm-confusion":"error","jwt-security/require-algorithm-whitelist":"error","jwt-security/no-decode-without-verify":"error","jwt-security/no-weak-secret":"error","jwt-security/no-hardcoded-secret":"error","jwt-security/no-timestamp-manipulation":"error","jwt-security/require-expiration":"error","jwt-security/no-sensitive-payload":"warn","jwt-security/require-issued-at":"warn"};const strictRules={"jwt-security/no-algorithm-none":"error","jwt-security/no-algorithm-confusion":"error","jwt-security/require-algorithm-whitelist":"error","jwt-security/no-decode-without-verify":"error","jwt-security/no-weak-secret":"error","jwt-security/no-hardcoded-secret":"error","jwt-security/require-expiration":"error","jwt-security/require-issued-at":"error","jwt-security/require-issuer-validation":"error","jwt-security/require-audience-validation":"error","jwt-security/no-timestamp-manipulation":"error","jwt-security/require-max-age":"error","jwt-security/no-sensitive-payload":"error"};const legacyRules={"jwt-security/no-algorithm-none":"error","jwt-security/no-algorithm-confusion":"error","jwt-security/no-hardcoded-secret":"warn"};exports.configs={flagship:{plugins:{"jwt-security":exports.plugin,jwt:exports.plugin},rules:{"jwt-security/no-algorithm-none":"error"}},recommended:{plugins:{"jwt-security":exports.plugin,jwt:exports.plugin},rules:recommendedRules},strict:{plugins:{"jwt-security":exports.plugin,jwt:exports.plugin},rules:strictRules},legacy:{plugins:{"jwt-security":exports.plugin,jwt:exports.plugin},rules:legacyRules},all:{plugins:{"jwt-security":exports.plugin,jwt:exports.plugin},rules:strictRules}};exports.default=exports.plugin;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.requireExpiration=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const utils_1=require("../../utils");const nest_modules_1=require("../../utils/nest-modules");exports.requireExpiration=(0,eslint_devkit_1.createRule)({name:"require-expiration",skipTestFiles:true,meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-jwt-security/docs/rules/require-expiration.md",description:"Require expiration claim (exp) or expiresIn option in JWT signing",cwe:"CWE-613",cvss:5.4},hasSuggestions:true,messages:{missingExpiration:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"Missing JWT Expiration",cwe:"CWE-613",description:"JWT without expiration is valid forever, increasing exposure window",severity:"MEDIUM",fix:'Add expiresIn: "1h" or exp claim to payload',documentationLink:"https://tools.ietf.org/html/rfc8725"}),addExpiration:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Add Expiration",description:"Add expiration to limit token lifetime",severity:"LOW",fix:'jwt.sign(payload, secret, { expiresIn: "1h" })',documentationLink:"https://www.npmjs.com/package/jsonwebtoken"})},schema:[{type:"object",properties:{maxExpirationSeconds:{type:"integer",default:86400,description:"Maximum allowed expiration time in seconds (24h default)"},trustedSanitizers:{type:"array",items:{type:"string"},default:[]},trustedAnnotations:{type:"array",items:{type:"string"},default:[]},strictMode:{type:"boolean",default:false}},additionalProperties:false}]},defaultOptions:[{maxExpirationSeconds:86400,trustedSanitizers:[],trustedAnnotations:[],strictMode:false}],create(context){const payloadHasExp=payloadNode=>{const resolved=payloadNode.type==="Identifier"?resolveObjectLiteral(payloadNode):payloadNode;if(resolved===null||resolved.type!=="ObjectExpression"){return false}return(0,utils_1.hasOption)(resolved,"exp")};const resolveObjectLiteral=node=>{let variable=null;let scope=context.sourceCode.getScope(node);while(scope!==null&&variable===null){variable=scope.variables.find(candidate=>candidate.name===node.name)??null;scope=scope.upper}if(variable===null||variable.defs.length!==1){return null}const definition=variable.defs[0];return definition.type==="Variable"?definition.node.init??null:null};const sourceCode=context.sourceCode;const JWS_ONLY_BUILDERS=new Set(["FlattenedSign","CompactSign","GeneralSign"]);return{CallExpression(node){if(!(0,utils_1.isSignOperation)(node,sourceCode)){return}if(node.arguments.length<1){return}const chain=(0,utils_1.joseBuilderChain)(node,sourceCode);if(chain!==null){if(JWS_ONLY_BUILDERS.has(chain.kind)||chain.calls.has("setExpirationTime")){return}const claims=chain.builder.arguments[0];if(claims!==void 0&&payloadHasExp(claims)){return}}else{const payloadArg=node.arguments[0];if(payloadHasExp(payloadArg)){return}const nestShaped=(0,utils_1.isNestJwtShape)(node,sourceCode)||node.arguments.length===1&&node.callee.type===eslint_devkit_1.AST_NODE_TYPES.MemberExpression&&node.callee.object.type!==eslint_devkit_1.AST_NODE_TYPES.CallExpression&&node.callee.object.type!==eslint_devkit_1.AST_NODE_TYPES.NewExpression;if(nestShaped){const own=(0,utils_1.resolveObject)(node.arguments[1],sourceCode);if(own!==null&&((0,utils_1.hasOption)(own,"expiresIn")||own.opaque)||(0,nest_modules_1.nestModuleExpiry)(context.filename,context.languageOptions.parser)!=="missing"){return}}else{const options=(0,utils_1.resolveCallOptions)(node,sourceCode);if(options!==null&&((0,utils_1.hasOption)(options,"expiresIn")||options.opaque)){return}}}const optionsArg3=node.arguments[(0,utils_1.isNestJwtShape)(node,sourceCode)?1:2];context.report({node,messageId:"missingExpiration",suggest:[{messageId:"addExpiration",fix(fixer){const sourceCode2=context.sourceCode;if(optionsArg3&&optionsArg3.type===eslint_devkit_1.AST_NODE_TYPES.ObjectExpression){const openBrace=sourceCode2.getFirstToken(optionsArg3);return fixer.insertTextAfter(openBrace," expiresIn: '1h',")}const lastArg=node.arguments[node.arguments.length-1];return fixer.insertTextAfter(lastArg,", { expiresIn: '1h' }")}}]})}}}});exports.default=exports.requireExpiration;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.requireExpiration=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const utils_1=require("../../utils");const lifetime_1=require("../../utils/lifetime");const nest_modules_1=require("../../utils/nest-modules");exports.requireExpiration=(0,eslint_devkit_1.createRule)({name:"require-expiration",skipTestFiles:true,meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-jwt-security/docs/rules/require-expiration.md",description:"Require expiration claim (exp) or expiresIn option in JWT signing",cwe:"CWE-613",cvss:5.4},hasSuggestions:true,messages:{missingExpiration:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"Missing JWT Expiration",cwe:"CWE-613",description:"JWT without expiration is valid forever, increasing exposure window",severity:"MEDIUM",fix:'Add expiresIn: "1h" or exp claim to payload',documentationLink:"https://tools.ietf.org/html/rfc8725"}),excessiveExpiration:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"Excessive JWT Expiration",cwe:"CWE-613",description:"JWT lives {{seconds}}s, longer than the configured maxExpirationSeconds ({{max}}s)",severity:"MEDIUM",fix:"Shorten expiresIn / exp to at most {{max}} seconds, and use a refresh token for longer sessions",documentationLink:"https://tools.ietf.org/html/rfc8725"}),addExpiration:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Add Expiration",description:"Add expiration to limit token lifetime",severity:"LOW",fix:'jwt.sign(payload, secret, { expiresIn: "1h" })',documentationLink:"https://www.npmjs.com/package/jsonwebtoken"})},schema:[{type:"object",properties:{maxExpirationSeconds:{type:"integer",description:"Maximum allowed token lifetime in seconds. Unset (the default) enforces no limit."},trustedSanitizers:{type:"array",items:{type:"string"},default:[]},trustedAnnotations:{type:"array",items:{type:"string"},default:[]},strictMode:{type:"boolean",default:false}},additionalProperties:false}]},defaultOptions:[{trustedSanitizers:[],trustedAnnotations:[],strictMode:false}],create(context){const maxExpirationSeconds=context.options[0]?.maxExpirationSeconds;const checkLifetime=(node,seconds)=>{if(maxExpirationSeconds===void 0||seconds===null||seconds<=maxExpirationSeconds){return}context.report({node,messageId:"excessiveExpiration",data:{seconds:String(seconds),max:String(maxExpirationSeconds)}})};const optionsLifetime=options=>(0,lifetime_1.expiresInSeconds)((0,utils_1.getOptionValue)(options,"expiresIn"),sourceCode);const payloadHasExp=payloadNode=>{const resolved=resolvePayload(payloadNode);if(resolved===null||resolved.type!=="ObjectExpression"){return false}return(0,utils_1.hasOption)(resolved,"exp")};const resolvePayload=payloadNode=>payloadNode.type==="Identifier"?resolveObjectLiteral(payloadNode):payloadNode;const resolveObjectLiteral=node=>{let variable=null;let scope=context.sourceCode.getScope(node);while(scope!==null&&variable===null){variable=scope.variables.find(candidate=>candidate.name===node.name)??null;scope=scope.upper}if(variable===null||variable.defs.length!==1){return null}const definition=variable.defs[0];return definition.type==="Variable"?definition.node.init??null:null};const sourceCode=context.sourceCode;const JWS_ONLY_BUILDERS=new Set(["FlattenedSign","CompactSign","GeneralSign"]);return{CallExpression(node){if(!(0,utils_1.isSignOperation)(node,sourceCode)){return}if(node.arguments.length<1){return}const chain=(0,utils_1.joseBuilderChain)(node,sourceCode);if(chain!==null){if(JWS_ONLY_BUILDERS.has(chain.kind)||chain.calls.has("setExpirationTime")){return}const claims=chain.builder.arguments[0];if(claims!==void 0&&payloadHasExp(claims)){return}}else{const payloadArg=node.arguments[0];if(payloadHasExp(payloadArg)){const exp=(0,utils_1.getOptionValue)(resolvePayload(payloadArg),"exp");checkLifetime(node,(0,lifetime_1.expClaimSeconds)(exp,sourceCode));return}const nestShaped=(0,utils_1.isNestJwtShape)(node,sourceCode)||node.arguments.length===1&&node.callee.type===eslint_devkit_1.AST_NODE_TYPES.MemberExpression&&node.callee.object.type!==eslint_devkit_1.AST_NODE_TYPES.CallExpression&&node.callee.object.type!==eslint_devkit_1.AST_NODE_TYPES.NewExpression;if(nestShaped){const own=(0,utils_1.resolveObject)(node.arguments[1],sourceCode);if(own!==null&&(0,utils_1.hasOption)(own,"expiresIn")){checkLifetime(node,optionsLifetime(own));return}if(own?.opaque===true||(0,nest_modules_1.nestModuleExpiry)(context.filename,context.languageOptions.parser)!=="missing"){return}}else{const options=(0,utils_1.resolveCallOptions)(node,sourceCode);if(options!==null&&(0,utils_1.hasOption)(options,"expiresIn")){checkLifetime(node,optionsLifetime(options));return}if(options?.opaque===true){return}}}const optionsArg3=node.arguments[(0,utils_1.isNestJwtShape)(node,sourceCode)?1:2];context.report({node,messageId:"missingExpiration",suggest:[{messageId:"addExpiration",fix(fixer){const sourceCode2=context.sourceCode;if(optionsArg3&&optionsArg3.type===eslint_devkit_1.AST_NODE_TYPES.ObjectExpression){const openBrace=sourceCode2.getFirstToken(optionsArg3);return fixer.insertTextAfter(openBrace," expiresIn: '1h',")}const lastArg=node.arguments[node.arguments.length-1];return fixer.insertTextAfter(lastArg,", { expiresIn: '1h' }")}}]})}}}});exports.default=exports.requireExpiration;
@@ -38,7 +38,7 @@ export interface NoWeakSecretOptions extends JwtRuleOptions {
38
38
  minSecretLength?: number;
39
39
  }
40
40
  export interface RequireExpirationOptions extends JwtRuleOptions {
41
- /** Maximum allowed expiration time in seconds. Default: 86400 (24 hours) */
41
+ /** Longest token lifetime allowed, in seconds. Unset (the default) enforces no limit. */
42
42
  maxExpirationSeconds?: number;
43
43
  }
44
44
  export interface RequireIssuerValidationOptions extends JwtRuleOptions {
@@ -1 +1 @@
1
- "use strict";var __createBinding=this&&this.__createBinding||(Object.create?(function(o,m,k,k2){if(k2===void 0)k2=k;var desc=Object.getOwnPropertyDescriptor(m,k);if(!desc||("get"in desc?!m.__esModule:desc.writable||desc.configurable)){desc={enumerable:true,get:function(){return m[k]}}}Object.defineProperty(o,k2,desc)}):(function(o,m,k,k2){if(k2===void 0)k2=k;o[k2]=m[k]}));var __setModuleDefault=this&&this.__setModuleDefault||(Object.create?(function(o,v){Object.defineProperty(o,"default",{enumerable:true,value:v})}):function(o,v){o["default"]=v});var __importStar=this&&this.__importStar||(function(){var ownKeys=function(o){ownKeys=Object.getOwnPropertyNames||function(o2){var ar=[];for(var k in o2)if(Object.prototype.hasOwnProperty.call(o2,k))ar[ar.length]=k;return ar};return ownKeys(o)};return function(mod){if(mod&&mod.__esModule)return mod;var result={};if(mod!=null){for(var k=ownKeys(mod),i=0;i<k.length;i++)if(k[i]!=="default")__createBinding(result,mod,k[i])}__setModuleDefault(result,mod);return result}})();Object.defineProperty(exports,"__esModule",{value:true});exports.parseSource=parseSource;exports.parseFileCached=parseFileCached;exports.relativeExportModule=relativeExportModule;exports.resolveSymbol=resolveSymbol;exports.bindsName=bindsName;const fs=__importStar(require("node:fs"));const path=__importStar(require("node:path"));const node_module_1=require("node:module");const eslint_devkit_1=require("@interlace/eslint-devkit");const value_flow_1=require("./value-flow");const MAX_FILE_HOPS=4;const RESOLUTION_SUFFIXES=["",".ts",".tsx",".js",".mjs",".cjs","/index.ts","/index.tsx","/index.js","/index.mjs","/index.cjs"];const parsed=new Map;function fallbackParser(){try{return(0,node_module_1.createRequire)(path.join(process.cwd(),"noop.js"))("@typescript-eslint/parser")}catch{return null}}function tryParse(candidate,code,filePath){const parser=candidate;if(!parser)return null;const options={ecmaVersion:"latest",sourceType:"module",range:true,loc:true,filePath};try{return parser.parseForESLint?parser.parseForESLint(code,options).ast:parser.parse(code,options)}catch{return null}}function parseSource(code,filePath,parser){return tryParse(parser,code,filePath)??tryParse(fallbackParser(),code,filePath)}function parseFileCached(filePath,parser){const mtimeMs=fs.statSync(filePath,{throwIfNoEntry:false})?.mtimeMs??-1;const cached=parsed.get(filePath);if(cached?.mtimeMs===mtimeMs)return cached.program;let program=null;try{program=parseSource(fs.readFileSync(filePath,"utf8"),filePath,parser)}catch{program=null}parsed.set(filePath,{mtimeMs,program});return program}function resolveRelative(fromFile,specifier){const base=path.resolve(path.dirname(path.resolve(fromFile)),specifier);const typescriptTwin=base.replace(/\.js$/,".ts");for(const candidate of[...RESOLUTION_SUFFIXES.map(suffix=>base+suffix),typescriptTwin]){if(fs.statSync(candidate,{throwIfNoEntry:false})?.isFile()){return candidate}}return null}function bindingModule(program,name){for(const stmt of program.body){if(stmt.type===eslint_devkit_1.AST_NODE_TYPES.ImportDeclaration){for(const spec of stmt.specifiers){if(spec.local.name!==name)continue;return{source:String(stmt.source.value),exportName:spec.type===eslint_devkit_1.AST_NODE_TYPES.ImportSpecifier?(0,eslint_devkit_1.objectKeyName)({key:spec.imported,computed:false}):null}}}if(stmt.type===eslint_devkit_1.AST_NODE_TYPES.VariableDeclaration){for(const declarator of stmt.declarations){const source=(0,value_flow_1.requireSpecifier)(declarator.init);if(source===null)continue;if(declarator.id.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&declarator.id.name===name){const init=declarator.init;return{source,exportName:init.type===eslint_devkit_1.AST_NODE_TYPES.MemberExpression?(0,eslint_devkit_1.propertyName)(init):null}}if(declarator.id.type===eslint_devkit_1.AST_NODE_TYPES.ObjectPattern){for(const prop of declarator.id.properties){if(prop.type===eslint_devkit_1.AST_NODE_TYPES.Property&&prop.value.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&prop.value.name===name){return{source,exportName:(0,eslint_devkit_1.objectKeyName)(prop)}}}}}}}return null}function exportedValue(program,name){for(const stmt of program.body){if(stmt.type===eslint_devkit_1.AST_NODE_TYPES.ExpressionStatement&&stmt.expression.type===eslint_devkit_1.AST_NODE_TYPES.AssignmentExpression&&stmt.expression.left.type===eslint_devkit_1.AST_NODE_TYPES.MemberExpression){const{left,right}=stmt.expression;const target=(0,eslint_devkit_1.propertyName)(left);if(target===name)return{kind:"value",node:right};if(target==="exports"&&right.type===eslint_devkit_1.AST_NODE_TYPES.ObjectExpression){for(const prop of right.properties){if(prop.type===eslint_devkit_1.AST_NODE_TYPES.Property&&(0,eslint_devkit_1.objectKeyName)(prop)===name){return{kind:"value",node:prop.value}}}}}if(stmt.type!==eslint_devkit_1.AST_NODE_TYPES.ExportNamedDeclaration)continue;if(stmt.declaration?.type===eslint_devkit_1.AST_NODE_TYPES.VariableDeclaration){for(const declarator of stmt.declaration.declarations){if(declarator.id.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&declarator.id.name===name&&declarator.init!==null){return{kind:"value",node:declarator.init}}}}for(const spec of stmt.specifiers){const exported=(0,eslint_devkit_1.objectKeyName)({key:spec.exported,computed:false});if(exported!==name)continue;const local=(0,eslint_devkit_1.objectKeyName)({key:spec.local,computed:false});return stmt.source?{kind:"reexport",source:String(stmt.source.value),exportName:local}:{kind:"value",node:{type:eslint_devkit_1.AST_NODE_TYPES.Identifier,name:local}}}}return null}function relativeExportModule(fromFile,specifier,exportName,parser,hops=0){if(hops>=MAX_FILE_HOPS)return null;const file=resolveRelative(fromFile,specifier);if(file===null)return null;const program=parseFileCached(file,parser);if(program===null)return null;const value=exportedValue(program,exportName);if(value===null)return null;let binding;if(value.kind==="reexport"){binding=value}else{const node=value.node;const required=(0,value_flow_1.requireSpecifier)(node);binding=required!==null?{source:required,exportName:node.type===eslint_devkit_1.AST_NODE_TYPES.MemberExpression?(0,eslint_devkit_1.propertyName)(node):null}:node.type===eslint_devkit_1.AST_NODE_TYPES.Identifier?bindingModule(program,node.name):null}if(binding===null)return null;if(!binding.source.startsWith("."))return binding.source;return binding.exportName===null?null:relativeExportModule(file,binding.source,binding.exportName,parser,hops+1)}function topLevelDeclaration(program,name){for(const stmt of program.body){const declaration=stmt.type===eslint_devkit_1.AST_NODE_TYPES.ExportNamedDeclaration||stmt.type===eslint_devkit_1.AST_NODE_TYPES.ExportDefaultDeclaration?stmt.declaration??stmt:stmt;if((declaration.type===eslint_devkit_1.AST_NODE_TYPES.FunctionDeclaration||declaration.type===eslint_devkit_1.AST_NODE_TYPES.ClassDeclaration||declaration.type===eslint_devkit_1.AST_NODE_TYPES.TSInterfaceDeclaration||declaration.type===eslint_devkit_1.AST_NODE_TYPES.TSTypeAliasDeclaration)&&declaration.id?.name===name){return declaration}if(declaration.type!==eslint_devkit_1.AST_NODE_TYPES.VariableDeclaration)continue;for(const declarator of declaration.declarations){if(declarator.id.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&declarator.id.name===name&&declarator.init!==null&&(0,value_flow_1.requireSpecifier)(declarator.init)===null){return declarator.init}}}return null}function loadRelative(module,specifier){const file=resolveRelative(module.filename,specifier);const program=file===null?null:parseFileCached(file,module.parser);return program===null?null:{program,filename:file,parser:module.parser}}function resolveExport(module,name,hops){if(hops>=MAX_FILE_HOPS)return null;const declared=topLevelDeclaration(module.program,name);if(declared!==null)return{kind:"local",node:declared,module};for(const stmt of module.program.body){if(stmt.type!==eslint_devkit_1.AST_NODE_TYPES.ExportNamedDeclaration)continue;for(const spec of stmt.specifiers){if((0,eslint_devkit_1.objectKeyName)({key:spec.exported,computed:false})!==name){continue}const local=(0,eslint_devkit_1.objectKeyName)({key:spec.local,computed:false});if(stmt.source===null)return resolveSymbol(module,local,hops+1);const source=String(stmt.source.value);if(!source.startsWith("."))return{kind:"external",source};const next=loadRelative(module,source);return next===null?null:resolveExport(next,local,hops+1)}}return null}function resolveSymbol(module,name,hops=0){const local=topLevelDeclaration(module.program,name);if(local!==null)return{kind:"local",node:local,module};const binding=bindingModule(module.program,name);if(binding===null)return null;if(!binding.source.startsWith(".")){return{kind:"external",source:binding.source}}if(binding.exportName===null)return null;const target=loadRelative(module,binding.source);return target===null?null:resolveExport(target,binding.exportName,hops+1)}function bindsName(module,name){return topLevelDeclaration(module.program,name)!==null||bindingModule(module.program,name)!==null}
1
+ "use strict";var __createBinding=this&&this.__createBinding||(Object.create?(function(o,m,k,k2){if(k2===void 0)k2=k;var desc=Object.getOwnPropertyDescriptor(m,k);if(!desc||("get"in desc?!m.__esModule:desc.writable||desc.configurable)){desc={enumerable:true,get:function(){return m[k]}}}Object.defineProperty(o,k2,desc)}):(function(o,m,k,k2){if(k2===void 0)k2=k;o[k2]=m[k]}));var __setModuleDefault=this&&this.__setModuleDefault||(Object.create?(function(o,v){Object.defineProperty(o,"default",{enumerable:true,value:v})}):function(o,v){o["default"]=v});var __importStar=this&&this.__importStar||(function(){var ownKeys=function(o){ownKeys=Object.getOwnPropertyNames||function(o2){var ar=[];for(var k in o2)if(Object.prototype.hasOwnProperty.call(o2,k))ar[ar.length]=k;return ar};return ownKeys(o)};return function(mod){if(mod&&mod.__esModule)return mod;var result={};if(mod!=null){for(var k=ownKeys(mod),i=0;i<k.length;i++)if(k[i]!=="default")__createBinding(result,mod,k[i])}__setModuleDefault(result,mod);return result}})();Object.defineProperty(exports,"__esModule",{value:true});exports.MAX_CACHED_MODULES=void 0;exports.cachedModuleCount=cachedModuleCount;exports.parseSource=parseSource;exports.parseFileCached=parseFileCached;exports.relativeExportModule=relativeExportModule;exports.resolveSymbol=resolveSymbol;exports.bindsName=bindsName;const fs=__importStar(require("node:fs"));const path=__importStar(require("node:path"));const node_module_1=require("node:module");const eslint_devkit_1=require("@interlace/eslint-devkit");const value_flow_1=require("./value-flow");const MAX_FILE_HOPS=4;const RESOLUTION_SUFFIXES=["",".ts",".tsx",".js",".mjs",".cjs","/index.ts","/index.tsx","/index.js","/index.mjs","/index.cjs"];exports.MAX_CACHED_MODULES=512;const parsed=(0,eslint_devkit_1.createLRUCache)(exports.MAX_CACHED_MODULES);function cachedModuleCount(){return parsed.size}function fallbackParser(){try{return(0,node_module_1.createRequire)(path.join(process.cwd(),"noop.js"))("@typescript-eslint/parser")}catch{return null}}function tryParse(candidate,code,filePath){const parser=candidate;if(!parser)return null;const options={ecmaVersion:"latest",sourceType:"module",range:true,loc:true,filePath};try{return parser.parseForESLint?parser.parseForESLint(code,options).ast:parser.parse(code,options)}catch{return null}}function parseSource(code,filePath,parser){return tryParse(parser,code,filePath)??tryParse(fallbackParser(),code,filePath)}function parseFileCached(filePath,parser){const mtimeMs=fs.statSync(filePath,{throwIfNoEntry:false})?.mtimeMs??-1;const cached=parsed.get(filePath);if(cached?.mtimeMs===mtimeMs)return cached.program;let program=null;try{program=parseSource(fs.readFileSync(filePath,"utf8"),filePath,parser)}catch{program=null}parsed.set(filePath,{mtimeMs,program});return program}function resolveRelative(fromFile,specifier){const base=path.resolve(path.dirname(path.resolve(fromFile)),specifier);const typescriptTwin=base.replace(/\.js$/,".ts");for(const candidate of[...RESOLUTION_SUFFIXES.map(suffix=>base+suffix),typescriptTwin]){if(fs.statSync(candidate,{throwIfNoEntry:false})?.isFile()){return candidate}}return null}function bindingModule(program,name){for(const stmt of program.body){if(stmt.type===eslint_devkit_1.AST_NODE_TYPES.ImportDeclaration){for(const spec of stmt.specifiers){if(spec.local.name!==name)continue;return{source:String(stmt.source.value),exportName:spec.type===eslint_devkit_1.AST_NODE_TYPES.ImportSpecifier?(0,eslint_devkit_1.objectKeyName)({key:spec.imported,computed:false}):null}}}if(stmt.type===eslint_devkit_1.AST_NODE_TYPES.VariableDeclaration){for(const declarator of stmt.declarations){const source=(0,value_flow_1.requireSpecifier)(declarator.init);if(source===null)continue;if(declarator.id.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&declarator.id.name===name){const init=declarator.init;return{source,exportName:init.type===eslint_devkit_1.AST_NODE_TYPES.MemberExpression?(0,eslint_devkit_1.propertyName)(init):null}}if(declarator.id.type===eslint_devkit_1.AST_NODE_TYPES.ObjectPattern){for(const prop of declarator.id.properties){if(prop.type===eslint_devkit_1.AST_NODE_TYPES.Property&&prop.value.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&prop.value.name===name){return{source,exportName:(0,eslint_devkit_1.objectKeyName)(prop)}}}}}}}return null}function exportedValue(program,name){for(const stmt of program.body){if(stmt.type===eslint_devkit_1.AST_NODE_TYPES.ExpressionStatement&&stmt.expression.type===eslint_devkit_1.AST_NODE_TYPES.AssignmentExpression&&stmt.expression.left.type===eslint_devkit_1.AST_NODE_TYPES.MemberExpression){const{left,right}=stmt.expression;const target=(0,eslint_devkit_1.propertyName)(left);if(target===name)return{kind:"value",node:right};if(target==="exports"&&right.type===eslint_devkit_1.AST_NODE_TYPES.ObjectExpression){for(const prop of right.properties){if(prop.type===eslint_devkit_1.AST_NODE_TYPES.Property&&(0,eslint_devkit_1.objectKeyName)(prop)===name){return{kind:"value",node:prop.value}}}}}if(stmt.type!==eslint_devkit_1.AST_NODE_TYPES.ExportNamedDeclaration)continue;if(stmt.declaration?.type===eslint_devkit_1.AST_NODE_TYPES.VariableDeclaration){for(const declarator of stmt.declaration.declarations){if(declarator.id.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&declarator.id.name===name&&declarator.init!==null){return{kind:"value",node:declarator.init}}}}for(const spec of stmt.specifiers){const exported=(0,eslint_devkit_1.objectKeyName)({key:spec.exported,computed:false});if(exported!==name)continue;const local=(0,eslint_devkit_1.objectKeyName)({key:spec.local,computed:false});return stmt.source?{kind:"reexport",source:String(stmt.source.value),exportName:local}:{kind:"value",node:{type:eslint_devkit_1.AST_NODE_TYPES.Identifier,name:local}}}}return null}function relativeExportModule(fromFile,specifier,exportName,parser,hops=0){if(hops>=MAX_FILE_HOPS)return null;const file=resolveRelative(fromFile,specifier);if(file===null)return null;const program=parseFileCached(file,parser);if(program===null)return null;const value=exportedValue(program,exportName);if(value===null)return null;let binding;if(value.kind==="reexport"){binding=value}else{const node=value.node;const required=(0,value_flow_1.requireSpecifier)(node);binding=required!==null?{source:required,exportName:node.type===eslint_devkit_1.AST_NODE_TYPES.MemberExpression?(0,eslint_devkit_1.propertyName)(node):null}:node.type===eslint_devkit_1.AST_NODE_TYPES.Identifier?bindingModule(program,node.name):null}if(binding===null)return null;if(!binding.source.startsWith("."))return binding.source;return binding.exportName===null?null:relativeExportModule(file,binding.source,binding.exportName,parser,hops+1)}function topLevelDeclaration(program,name){for(const stmt of program.body){const declaration=stmt.type===eslint_devkit_1.AST_NODE_TYPES.ExportNamedDeclaration||stmt.type===eslint_devkit_1.AST_NODE_TYPES.ExportDefaultDeclaration?stmt.declaration??stmt:stmt;if((declaration.type===eslint_devkit_1.AST_NODE_TYPES.FunctionDeclaration||declaration.type===eslint_devkit_1.AST_NODE_TYPES.ClassDeclaration||declaration.type===eslint_devkit_1.AST_NODE_TYPES.TSInterfaceDeclaration||declaration.type===eslint_devkit_1.AST_NODE_TYPES.TSTypeAliasDeclaration)&&declaration.id?.name===name){return declaration}if(declaration.type!==eslint_devkit_1.AST_NODE_TYPES.VariableDeclaration)continue;for(const declarator of declaration.declarations){if(declarator.id.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&declarator.id.name===name&&declarator.init!==null&&(0,value_flow_1.requireSpecifier)(declarator.init)===null){return declarator.init}}}return null}function loadRelative(module,specifier){const file=resolveRelative(module.filename,specifier);const program=file===null?null:parseFileCached(file,module.parser);return program===null?null:{program,filename:file,parser:module.parser}}function resolveExport(module,name,hops){if(hops>=MAX_FILE_HOPS)return null;const declared=topLevelDeclaration(module.program,name);if(declared!==null)return{kind:"local",node:declared,module};for(const stmt of module.program.body){if(stmt.type!==eslint_devkit_1.AST_NODE_TYPES.ExportNamedDeclaration)continue;for(const spec of stmt.specifiers){if((0,eslint_devkit_1.objectKeyName)({key:spec.exported,computed:false})!==name){continue}const local=(0,eslint_devkit_1.objectKeyName)({key:spec.local,computed:false});if(stmt.source===null)return resolveSymbol(module,local,hops+1);const source=String(stmt.source.value);if(!source.startsWith("."))return{kind:"external",source};const next=loadRelative(module,source);return next===null?null:resolveExport(next,local,hops+1)}}return null}function resolveSymbol(module,name,hops=0){const local=topLevelDeclaration(module.program,name);if(local!==null)return{kind:"local",node:local,module};const binding=bindingModule(module.program,name);if(binding===null)return null;if(!binding.source.startsWith(".")){return{kind:"external",source:binding.source}}if(binding.exportName===null)return null;const target=loadRelative(module,binding.source);return target===null?null:resolveExport(target,binding.exportName,hops+1)}function bindsName(module,name){return topLevelDeclaration(module.program,name)!==null||bindingModule(module.program,name)!==null}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.msStringSeconds=msStringSeconds;exports.expiresInSeconds=expiresInSeconds;exports.expClaimSeconds=expClaimSeconds;const eslint_devkit_1=require("@interlace/eslint-devkit");const value_flow_1=require("./value-flow");const UNIT_SECONDS=new Map([...["years","year","yrs","yr","y"].map(u=>[u,31557600]),...["weeks","week","w"].map(u=>[u,604800]),...["days","day","d"].map(u=>[u,86400]),...["hours","hour","hrs","hr","h"].map(u=>[u,3600]),...["minutes","minute","mins","min","m"].map(u=>[u,60]),...["seconds","second","secs","sec","s"].map(u=>[u,1]),...["milliseconds","millisecond","msecs","msec","ms"].map(u=>[u,.001])]);const MS_STRING=/^(-?(?:\d+)?\.?\d+) *([a-z]*)$/i;function msStringSeconds(text){const match=MS_STRING.exec(text);if(match===null)return null;const unit=match[2].toLowerCase();const perUnit=unit===""?.001:UNIT_SECONDS.get(unit);return perUnit===void 0?null:Number(match[1])*perUnit}function expiresInSeconds(node,sourceCode){const text=(0,eslint_devkit_1.staticString)((0,value_flow_1.resolveTerminal)(node,sourceCode));return text===null?(0,value_flow_1.staticNumber)(node,sourceCode):msStringSeconds(text)}const ROUNDING=new Set(["Math.floor","Math.round","Math.trunc","Math.ceil"]);function calleeName(node){return(0,eslint_devkit_1.memberPath)(node.callee)?.join(".")??null}function isNowInSeconds(node,sourceCode){const value=(0,value_flow_1.resolveTerminal)(node,sourceCode);if(value.type===eslint_devkit_1.AST_NODE_TYPES.CallExpression&&ROUNDING.has(calleeName(value))&&value.arguments.length===1){return isNowInSeconds(value.arguments[0],sourceCode)}return value.type===eslint_devkit_1.AST_NODE_TYPES.BinaryExpression&&value.operator==="/"&&(0,value_flow_1.staticNumber)(value.right,sourceCode)===1e3&&value.left.type===eslint_devkit_1.AST_NODE_TYPES.CallExpression&&calleeName(value.left)==="Date.now"}function expClaimSeconds(node,sourceCode){const value=(0,value_flow_1.resolveTerminal)(node,sourceCode);if(value.type!==eslint_devkit_1.AST_NODE_TYPES.BinaryExpression||value.operator!=="+"){return null}if(isNowInSeconds(value.left,sourceCode)){return(0,value_flow_1.staticNumber)(value.right,sourceCode)}return isNowInSeconds(value.right,sourceCode)?(0,value_flow_1.staticNumber)(value.left,sourceCode):null}