UNPKG

@stoplight/spectral-owasp-ruleset

Version:

Probably don't want to beg hackers to come and take your stuff.

105 lines (95 loc) 2.8 kB
import { createRulesetFunction, IFunctionResult, } from "@stoplight/spectral-core"; /** * @author Roberto Polli <https://github.com/ioggstream> */ const getAllOperations = function* (paths: any): any { if (typeof paths !== "object") { return; } const validMethods = [ "get", "head", "post", "put", "patch", "delete", "options", "trace", ]; const operation = { path: "", operation: "" }; for (const idx of Object.keys(paths)) { const path = paths[idx]; if (typeof path === "object") { operation.path = idx; for (const httpMethod of Object.keys(path)) { typeof path[httpMethod] === "object" && validMethods.includes(httpMethod) && ((operation.operation = httpMethod), yield operation); } } } }; export default createRulesetFunction( { input: null, options: { type: "object", additionalProperties: false, properties: { adminUrl: { type: "string", }, }, required: [], }, }, function differentSecuritySchemes( input: any, options: any ): IFunctionResult[] { const errorList = []; const nonAdminSecurityHashes = []; const adminSecurityEntries = []; const { adminUrl = "/admin" } = options; const { paths } = input; for (const { path, operation: httpMethod } of getAllOperations(paths)) { let { security: operationSecurity } = paths[path][httpMethod]; // No security so skip this and leave it for other rules which check for security. if (operationSecurity === undefined) { continue; } if (Array.isArray(operationSecurity)) { for (const [idx, securityEntry] of operationSecurity.entries()) { if (typeof securityEntry !== "object") { continue; } // This creates a string for easier comparison to see if its used elsewhere, but // this might not be tough enough for some of the weirder edge cases. const securityHash = JSON.stringify(securityEntry); if (path.includes(adminUrl)) { adminSecurityEntries.push({ uri: path, hash: securityHash, path: ["paths", path, httpMethod, "security", idx], }); } else { nonAdminSecurityHashes.push(securityHash); } } } } // For every admin security entry, check if it is used in a non-admin path. for (const { uri, hash, path } of adminSecurityEntries) { if (nonAdminSecurityHashes.includes(hash)) { errorList.push({ message: `Admin endpoint ${uri} has the same security requirement as a non-admin endpoint.`, path, }); } } return errorList; } );