{"record":{"id":"cca85abc6c1cec3b","repo":"babalae/better-genshin-impact","slug":"js-url-url-manifest-json-http-a","errorCode":null,"errorMessage":"当前JS脚本不允许请求此URL: {url}，请在脚本的manifest.json中配置http_allowed_urls，当前允许的URL列表: [{string.Join(\", \", allowedUrls)}]","messagePattern":"当前JS脚本不允许请求此URL: (.+?)，请在脚本的manifest\\.json中配置http_allowed_urls，当前允许的URL列表: \\[(.+?)\\]","errorType":"exception","errorClass":"UnauthorizedAccessException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/Core/Script/Dependence/Http.cs","lineNumber":43,"sourceCode":"            throw new UnauthorizedAccessException(\"当前JS脚本不允许使用HTTP请求，请在调度器通用设置中启用“JS HTTP权限”\");\n        }\n        var allowedUrls = currentProject?.Project?.Manifest.HttpAllowedUrls ?? [];\n        if (allowedUrls.Length == 0)\n        {\n            throw new UnauthorizedAccessException(\"当前JS脚本没有配置允许请求的URL，请在脚本的manifest.json中配置http_allowed_urls\");\n        }\n        if (allowedUrls.Any(allowedUrl =>\n        {\n            // fuzzy match\n            var pattern = \"^\" + System.Text.RegularExpressions.Regex.Escape(allowedUrl).Replace(\"\\\\*\", \".*\") + \"$\";\n            _logger.LogDebug($\"[HTTP] 检查URL {url} 是否符合: {pattern}\");\n            var regex = new System.Text.RegularExpressions.Regex(pattern);\n            return regex.IsMatch(url);\n        }))\n        {\n            return;\n        }\n        throw new UnauthorizedAccessException($\"当前JS脚本不允许请求此URL: {url}，请在脚本的manifest.json中配置http_allowed_urls，当前允许的URL列表: [{string.Join(\", \", allowedUrls)}]\");\n    }\n\n    public class HttpReponse\n    {\n        public int status_code { get; set; }\n        public Dictionary<string, string> headers { get; set; } = new();\n        public string body { get; set; } = \"\";\n    }\n\n\n    /// <summary>\n    /// 执行HTTP请求\n    /// </summary>\n    /// <param name=\"method\">HTTP方法</param>\n    /// <param name=\"url\">请求URL</param>\n    /// <param name=\"body\">请求体</param>\n    /// <param name=\"headersJson\">请求头，JSON格式</param>\n    /// <returns></returns>","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/Core/Script/Dependence/Http.cs#L25-L61","documentation":"Thrown as UnauthorizedAccessException by Http.CheckHttpPermission when the target URL does not match any pattern in the project's http_allowed_urls allowlist. The matching uses a fuzzy regex: each allowed URL is escaped, '*' is converted to '.*', and the full string is anchored with ^...$. If no pattern matches the requested URL, access is denied.","triggerScenarios":"Calling http.get(url) or http.post(url) where url is not covered by any pattern in manifest.json's http_allowed_urls. For example, the allowlist has \"https://api.example.com/v1/*\" but the script requests \"https://api.example.com/v2/data\".","commonSituations":"URL path prefix changed (API version bump). Wildcard pattern is too narrow — e.g., \"https://api.example.com/users\" instead of \"https://api.example.com/*\". Different subdomain used (cdn.example.com vs api.example.com). HTTP vs HTTPS mismatch in the pattern.","solutions":["Add the specific URL or a broader wildcard pattern to http_allowed_urls in manifest.json.","Use broader wildcards for flexibility: \"https://*.example.com/*\" or \"https://api.example.com/*\".","Verify the exact URL being requested (including protocol, subdomain, path) against the allowlist patterns.","Note that '*' becomes '.*' in regex — it matches any characters, not just path segments."],"exampleFix":"// before — manifest.json\n\"http_allowed_urls\": [\"https://api.example.com/v1/*\"]\n\n// script requests\nhttp.get(\"https://api.example.com/v2/data\") // denied\n\n// after — manifest.json\n\"http_allowed_urls\": [\n  \"https://api.example.com/v1/*\",\n  \"https://api.example.com/v2/*\"\n]\n// or broader\n\"http_allowed_urls\": [\"https://api.example.com/*\"]","handlingStrategy":"validation","validationCode":"// Pre-check URL against allowlist patterns\nvar project = TaskContext.Instance().CurrentScriptProject;\nvar allowedUrls = project?.Project?.Manifest.HttpAllowedUrls ?? [];\nbool isAllowed = allowedUrls.Any(pattern =>\n{\n    var regexPattern = \"^\" + Regex.Escape(pattern).Replace(\"\\\\*\", \".*\") + \"$\";\n    return Regex.IsMatch(url, regexPattern);\n});\nif (!isAllowed)\n    throw new UnauthorizedAccessException($\"URL {url} not in allowlist: [{string.Join(\", \", allowedUrls)}]\");","typeGuard":null,"tryCatchPattern":"try\n{\n    var resp = http.Get(url, headers);\n}\ncatch (UnauthorizedAccessException ex) when (ex.Message.Contains(\"不允许请求此URL\"))\n{\n    _logger.LogError(\"URL {Url} not allowed. Current allowlist: see manifest.json http_allowed_urls\", url);\n}","preventionTips":["Match exact protocol (http vs https) and subdomain in allowlist patterns.","Use broad wildcards (https://api.example.com/*) unless security requires narrower patterns.","Remember '*' matches any characters (.*), not just path segments.","Update the allowlist when API endpoints or versions change."],"tags":["security","permission","http","url-matching","config","manifest","allowlist"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}