All Products
Search
Document Center

Qoder CN Series:Configure filters

Last Updated:Sep 24, 2026

Administrators of Qoder CN Enterprise Dedicated Edition and organization-wide administrators can configure security filters for AI chat, code completion, and knowledge base uploads.

Important

The new Qoder CN documentation site is now available. Content on this site may not reflect the latest product features and changes. Visit docs.qoder.cn for the latest product documentation.

This feature supports only Visual Studio Code and JetBrains IDE extensions. It is not available in the Qoder CN IDE.

Applicable editions

Enterprise Dedicated Edition

Access the feature

  1. Log in to the Qoder CN console as a Qoder CN administrator or an organization-wide administrator (Enterprise Dedicated Edition only). In the left navigation pane, choose Policy Configuration > Filter Configuration.

  2. At the top of the page, select a tab based on the scenario where you want to apply the filter: AI Chat, Inline Code Generation, or Knowledge Base Upload (Enterprise Dedicated Edition only).

  3. Enable the switch for each filter and configure its parameters. The following table lists the supported filter types:

    Scenario

    Filter type

    Description

    AI Chat

    AI Chat pre-filter

    When you use the AI Chat feature of Qoder CN, user input sent to the Large Language Model (LLM) passes through the pre-filter. LLM output passes through the post-filter.

    AI Chat post-filter

    Inline Code Generation

    Inline Code Generation pre-filter

    When you use the Inline Code Generation feature of Qoder CN, user input sent to the LLM passes through the pre-filter. LLM output passes through the post-filter.

    Inline Code Generation post-filter

    Knowledge Base Upload

    Knowledge Base Upload pre-filter

    Files uploaded to the Qoder CN knowledge base must pass this filter before upload succeeds.

    Important
    • Ensure developers upgrade their Qoder CN extension to version 1.4.0 or later. Otherwise, configured filters will not take effect.

    • After you enable or modify the AI Chat filter or Inline Code Generation filter, changes take about 5 to 10 minutes to take effect for developers using the Qoder CN extension.

    • After you enable or modify the Knowledge Base Upload filter, changes take effect immediately. Files uploaded to your enterprise knowledge base are filtered right away.

Configure pre-filters for AI Chat and Inline Code Generation

Method 1: Configure with regular expressions

Note

Thoroughly test regular expressions before deployment to avoid performance issues in IDE extensions.

  • Processing method: Configure filters using regular expressions. Three modes are supported.

    No action on match

    Take no action when a match occurs.

    Block on match

    Block the request and stop the model call when a match occurs.

    Replace on match

    Replace content according to the configuration when a match occurs.

  • Notification: Enable notifications to send alerts to your preferred messaging platform using webhooks.

  • Execution order: Filters run in the order you configure them.

  • Maximum number of regular expressions: You can add up to 10 expressions.

  • Regular expression standard: Expressions follow the ECMAScript standard. Common flags such as i (case-insensitive), g (global), and s (DOTALL) are supported.

  • Example configurations:

    Rule name

    Regular expression

    Replacement

    Original text

    Replaced text

    ID number

    (?<pre>.*)(\d{15})((\d{2})([0-9Xx]))(?<post>.*)

    $<pre>***$<post>

    ID number: 330204197709022312.

    ID number: ***.

    Email address

    \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*

    ***

    My email is lin***@aliyunmail.com

    My email is ***

    Password

    (.*password=)([\w\d]+)(.*)

    $1***$3

    {password=1213213}

    {password=***}

Method 2: Configure with custom scripts (Enterprise Dedicated Edition only)

The Enterprise Dedicated Edition supports custom script-based filtering for complex pre-filtering scenarios.

Step 1: Develop the script

Write scripts in TypeScript using the sample code as a reference.

  1. Download the template repository: Click the repository URL: lingma-extension-template. This template includes scaffolding for script development. Read the README.md file and code examples carefully.

  2. Implement the pre-processing interface: Implement the RequestPreHandler interface. For API details, see Custom Script API. Here is an example implementation in SensitiveContentFilter.ts:

    /**
     * Sensitive content filter. Pre-processes data sent to the model.
     */
    export const sensitiveContentFilter: RequestPreHandler = {
      handle: async (request: RawRequest, SDKTool: Qoder CNSDKTool) => {
        const dataMap = PayloadUtil.getPayloadData(request.payload);
        for (const [key, value] of dataMap.entries()) {
          if (value.includes('password')) {
            return ResultUtil.buildBlockResult('Content contains password');
          }
        }
        // Handle different actions differently
        switch (request.action) {
          case ActionEnum.COMPLETION:
            // do something
            break;
          case ActionEnum.CODE_PROBLEM_SOLVE:
            // do something
            break;
          default:
            return ResultUtil.buildNoOpsResult();
        }
        return ResultUtil.buildNoOpsResult();
      },
    };
  3. Run and debug the script. Test it by running the main function. Follow these steps:

    Step 1

    Edit the src/index.ts file. Modify the main function to test your script. Example:

    async function main() {
      const value1 = ['password=123', 'abc'];
      const value2 = 'hello world';
      const dataMap = new Map<PayloadDataKeyEnum, PayloadDataValueType>();
      dataMap.set(PayloadDataKeyEnum.SELECTED_CODE, value1);
      dataMap.set(PayloadDataKeyEnum.USER_INPUT, value2);
    
      const mockRequest: RawRequest = {
        action: ActionEnum.CODE_GENERATE_COMMENT,
        payload: {
          associatedContexts: [],
          data: dataMap,
        },
        requestId: '123',
      };
      const response = await sensitiveContentFilter.handle(mockRequest, SDKTool);
      console.log(response);
    }

    Step 2

    In VS Code, open the script file and set breakpoints. Then, in the Debug view, select Launch Program and click Run.

    The sample code file index.ts contains the following content.

    import { sensitiveContentFilter } from './demo/SensitiveContentFilter';
    import { ActionEnum, PayloadDataKeyEnum, PayloadDataValueType, RawRequest } from './sdk/RequestPreHxxx';
    
    const SDKTool = {
      idePlatform: 'vscode',
      ideVersion: '1.0',
      pluginVersion: '1.0',
      user: {
        name: 'tester',
        organizationId: '123',
        organizationName: 'test_org',
        uid: 'org_123',
      },
    };

Step 2: Compile and Build

Compile TypeScript to JavaScript. For example, compile SensitiveContentFilter.ts into SensitiveContentFilter.js:

  1. Open the configuration file src/build.js. Update the entryPoints and outfile parameters. Set entryPoints to the path of your TypeScript file. Set outfile to the output path for the compiled JavaScript file.

  2. Run the command node build.js from the root directory of your repository. After successful execution, the JavaScript file appears at the path specified in outfile.

Step 3: Test locally

Test the script locally before uploading to verify it integrates with the Qoder CN IDE extension and filters correctly.

  1. Copy the compiled JavaScript file to the /extension/local/script/ directory under the local storage path of Qoder CN.

  2. Edit the config.json file. This file is located in the /extension/local/ directory under the local storage path of Qoder CN. Open config.json and find contentHandlerScripts. Add your script's configuration. If contentHandlerScripts does not exist, create a new array. Example:

    {
      "contentHandlerScripts": [
        {
          "identifier": "SensitiveContentFilter", 
          "name": "Sensitive Content Filter",
          "version": "1.0.0",
          "scriptPath": "~/.lingma/extension/local/script/SensitiveContentFilter.js",
          "state": "enabled",
          "bizType": "completion"
        }
      ]
    }

    Parameter descriptions:

    Parameter

    Description

    identifier

    Script ID. Must be unique.

    name

    Script name.

    version

    Script version. Increment after each change, or the updated script will not take effect.

    scriptPath

    Script file path. Note:

    • The script must be placed in the /extension/local/script/ directory under the local storage path.

    • The JavaScript file name (for example, SensitiveContentFilter.js) must match the identifier value.

    state

    Script state. enabled enables the script. disabled disables it.

    bizType

    Business scenario. completion applies to inline code generation. chat applies to AI chat.

Step 4: Upload the script

After local testing, upload the script:

  1. Go to the Qoder CN console. Choose Policy Management. Select the scenario where you want to enable the security filter.

  2. Select Custom Script as the filter option.

  3. Upload the compiled JavaScript file.

  4. Click Save Configuration. The configuration takes effect on the extension within about 5 minutes.

Custom Script API

Custom scripts support three processing methods:

  • Block: Stop further processing. No inference call is made to the LLM. The current request ends.

  • Filter: Modify the data sent (for example, obfuscate, delete, or replace content), then continue processing.

  • No operation: Return the data unchanged and continue processing.

Interface definition
/**
 * Pre-processing interface for Qoder CN
 */
export interface RequestPreHandler {
  // Process the request
  handle: (request: RawRequest, SDKTool: Qoder CNSDKTool) => Promise<HandlerResponse>;
}
Input parameters
/**
 * Request object. Includes the action and raw data sent to the LLM.
 */
export interface RawRequest {
  // Unique identifier for the request. Used for tracing.
  action: ActionEnum;
  // Enum for the action that triggered the request.
  payload: ContentPayload;
  // Payload containing raw data.
  requestId: string;
}

// Value type for ContentPayload.data
export type PayloadDataValueType = string | number | string[];
/**
 * Payload containing raw data sent to the LLM.
 */
export class ContentPayload {
  // Collection of data to process. Keys are defined in ContextValueKeyEnum.
  data: Map<PayloadDataKeyEnum, PayloadDataValueType>;
  // Context associated with the processing.
  associatedContexts: ContextItem[];

  constructor() {
    this.data = new Map<PayloadDataKeyEnum, PayloadDataValueType>();
    this.associatedContexts = [];
  }
}

/**
 * Keys for ContentPayload.data
 */
export enum PayloadDataKeyEnum {
  // Selected code snippet
  SELECTED_CODE ='lingma:code',
  // User input text
  USER_INPUT = 'lingma:text',
  // Error messages
  ERROR_MESSAGES = 'lingma:error_messages',
  // Terminal log output
  TERMINAL_CONTENT = 'lingma:terminal_content',
  // Code before cursor for code completion
  PREFIX_CODE = 'lingma:code_prefix',
  // Code after cursor for code completion
  SUFFIX_CODE = 'lingma:code_suffix',
  // Similar code snippets
  SIMILAR_CODE = 'lingma:similar_code',
}

/**
 * Enum for request actions
 */
export enum ActionEnum {
    // Unit test
    GENERATE_TESTCASE           = 'GENERATE_TESTCASE',
    // Generate comments
    CODE_GENERATE_COMMENT       = 'CODE_GENERATE_COMMENT',
    // Explain code
    EXPLAIN_CODE                = 'EXPLAIN_CODE',
    // Optimize code
    OPTIMIZE_CODE               = 'OPTIMIZE_CODE',
    // Free input (direct text entry in the chat box)
    FREE_INPUT                  = 'FREE_INPUT',
    // Quick fix for code issues
    CODE_PROBLEM_SOLVE          = 'CODE_PROBLEM_SOLVE',
    // Generate shell commands
    TERMINAL_COMMAND_GENERATION = 'TERMINAL_COMMAND_GENERATION',
    // Fix terminal errors
    TERMINAL_EXPLAIN_FIX        = 'TERMINAL_EXPLAIN_FIX',
    // Code completion
    COMPLETION                  = 'COMPLETION',
}
Output parameters
/**
 * Pre-processing result
 */
export class HandlerResponse {
  // Processing policy. Controls subsequent logic.
  handlePolicy: HandlePolicy;
  // Reason description
  reason?: string;
  // Required when handlePolicy=FILTER. Contains filtered data. Must match ContentRequest.payload structure.
  payload?: ContentPayload;
  constructor() {
    // Default values
    // eslint-disable-next-line @typescript-eslint/no-use-before-define
    this.handlePolicy = HandlePolicy.NO_OPS;
    this.reason = '';
    this.payload = new ContentPayload();
  }
}

/**
 * Processing policy enum
 */
export enum HandlePolicy {
  // Block the request
  BLOCK = 'BLOCK',
  // Filter the request and modify the payload
  FILTER = 'FILTER',
  // Take no action
  NO_OPS = 'NO_OPS',
}

Configure post-filters for AI Chat and Inline Code Generation

Method 1: Configure with regular expressions

Note

Thoroughly test regular expressions before deployment to avoid performance issues in IDE extensions.

  • Processing method: Configure filters using regular expressions. Only one mode is supported:

    No action on match

    Take no action when a match occurs.

  • Notification: Enable notifications to send alerts to your preferred messaging platform using webhooks.

  • Execution order: Filters run in the order you configure them.

  • Maximum number of regular expressions: You can add up to 10 expressions.

  • Regular expression standard: Expressions follow the ECMAScript standard. Common flags such as i (case-insensitive), g (global), and s (DOTALL) are supported.

  • Example configurations:

    Rule name

    Regular expression

    Original text

    ID number

    (?<pre>.*)(\d{15})((\d{2})([0-9Xx]))(?<post>.*)

    ID number: 330204197709022312.

    Email address

    \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*

    My email is lin***@aliyunmail.com

    Password

    (.*password=)([\w\d]+)(.*)

    {password=1213213}

Method 2: Configure with custom scripts (Enterprise Dedicated Edition only)

The Enterprise Dedicated Edition supports custom script-based filtering for complex post-filtering scenarios.

Step 1: Develop the script

Write scripts in TypeScript using the sample code as a reference.

  1. Download the template repository: Click the repository URL: lingma-extension-template. This template includes scaffolding for script development. Read the README.md file and code examples carefully.

  2. Implement the post-processing interface: Implement the RequestPostHandler interface. For the API, refer to Custom Script API. The following is an implementation example from the code snippet LLMChatAuditHandler.ts, which audits AIChat operations of Qoder CN and reports the audit content to Alibaba Cloud SLS.

    import {ResultUtil} from '../common/HandlerRespUtil';
    import { JsonUtil } from '../common/JsonUtil';
    import {PayloadUtil} from '../common/PayloadUtil';
    import {Config} from '../sdk/ConfigManager';
    import {Qoder CNSDKTool} from '../sdk/Qoder CNSDKTool';
    import axios from "axios";
    import moment from "moment";
    import os from "os";
    import {
      ActionEnum, AIResponse,
      HandlePolicy,
      RawRequest,
      RequestPostHandler,
      RequestPreHandler
    } from '../sdk/RequestHandleSDK';
    
    /**
     * Custom post-filter script. Sends request content to a remote server for processing (such as code scanning or content auditing).
     */
    export const llmResultAuditHandler: RequestPostHandler = {
      handle: async (request: RawRequest, response: AIResponse,SDKTool: Qoder CNSDKTool) => {
         // Operator name
         let userName = SDKTool.user.name;
         // Operator ID
         let userId = SDKTool.user.uid;
         // IDE
         let ide = SDKTool.idePlatform;
         // IDE version
         let ideVersion = SDKTool.ideVersion;     
         // Operation time
         let operationTime = moment().format("YYYY-MM-DD HH:mm:ss");
         // Operation IP
         let opeartionIp = getIpAddress();
         // Business scenario (completion or chat)
         let bizType = "chat";
         // Request ID
         let requestId = request.requestId;
         // Action
         let action = request.action;
         // Operation content (select fields based on your audit needs. Avoid large payloads over 16 KB.)
         let inferredResult = response.inferredResult.text;
        
         // Report to SLS
         // SLS project name
         let slsProject = "xxx";
         // SLS LogStore name
         let slsLogStore = "xxx";
         // SLS endpoint
         let endPoint = "cn-hangzhou.log.aliyuncs.com";
         let slsWebTrackingUrl = `http://${slsProject}.${endPoint}/logstores/${slsLogStore}/track?APIVersion=0.6.0&request_id=${requestId}&action=${action}&biz_type=${bizType}&user_name=${userName}&user_id=${userId}&ide=${ide}&ide_version=${ideVersion}&operation_time=${operationTime}&opeartion_ip=${opeartionIp}&inferredResult=${inferredResult}`;
         axios.get(slsWebTrackingUrl).catch((error) => {
           console.error(error);
         });
    
         // Return filter result
        return ResultUtil.buildPostHandlerResponse(HandlePolicy.NO_OPS, response.inferredResult,'No action required');
      },
    };
    
    /**
     * Add the custom script filter to the configuration
     * @param config Config object provided by Qoder CNExtensionSDK
     */
    export function modifyConfig(config: Config) {
      config.postContentHandlers.push(llmResultAuditHandler);
      return config;
    }
    
    function getIpAddress() {
      const interfaces = os.networkInterfaces();
      for (let devName in interfaces) {
        let iface = interfaces[devName];
    
        for (let i = 0; i < iface.length; i++) {
          let alias = iface[i];
          if (
            alias.family === "IPv4" &&
            alias.address !== "127.0.0.1" &&
            !alias.internal
          )
            return alias.address;
        }
      }
    
      return "No IP address found";
    }
  3. Run and debug the script. Test it by running the main function. Follow these steps:

    Step 1

    Edit the src/index.ts file. Modify the main function to test your script. Example:

    async function main() {
      const value2 = 'hello world';
      const dataMap = new Map<PayloadDataKeyEnum, PayloadDataValueType>();
      dataMap.set(PayloadDataKeyEnum.USER_INPUT, value2);
    
      const request: RawRequest = {
        action: ActionEnum.CODE_GENERATE_COMMENT,
        payload: {
          associatedContexts: [],
          data: dataMap,
        },
        requestId: 'test-request-id',
      };
    
      const aiResponse: AIResponse = {
        inferredResult: {
          text: 'reply hello world',
        },
      };
    
      const response = await llmResultAuditHandler.handle(request, aiResponse, SDKTool);
      console.log(response);
    }

    Step 2

    In VS Code, open the script file and set breakpoints. Then, in the Debug view, select Launch Program and click Run.

    The sample code file index.ts contains the following content.

    import { sensitiveContentFilter } from './demo/SensitiveContentFilter';
    import { ActionEnum, PayloadDataKeyEnum, PayloadDataValueType, RawRequest } from './sdk/RequestPreHxxx';
    
    const SDKTool = {
      idePlatform: 'vscode',
      ideVersion: '1.0',
      pluginVersion: '1.0',
      user: {
        name: 'tester',
        organizationId: '123',
        organizationName: 'test_org',
        uid: 'org_123',
      },
    };

Step 2: Compile and Build

Compile TypeScript to JavaScript. For example, compile LLMChatAuditHandler.ts into LLMChatAuditHandler.js:

  1. Open the configuration file src/build.js. Update the entryPoints and outfile parameters. Set entryPoints to the path of your TypeScript file. Set outfile to the output path for the compiled JavaScript file.

  2. Run the command node build.js from the root directory of your repository. After successful execution, the JavaScript file appears at the path specified in outfile.

Step 3: Test locally

Test the script locally before uploading to verify it integrates with the Qoder CN IDE extension and filters correctly.

  1. Copy the compiled JavaScript file to the /extension/local/script/ directory under the local storage path of Qoder CN.

  2. Edit the config.json file. This file is located in the /extension/local/ directory under the local storage path of Qoder CN. Open config.json and find contentHandlerScripts. Add your script's configuration. If contentHandlerScripts does not exist, create a new array. Example:

    {
      "contentHandlerScripts": [
        {
          "identifier": "LLMChatAuditHandler", 
          "name": "AI Chat Audit",
          "version": "1.0.0",
          "scriptPath": "~/.lingma/extension/local/script/LLMChatAuditHandler.js",
          "state": "enabled",
          "stage":"post",
          "bizType": "completion"
        }
      ]
    }

    Parameter descriptions:

    Parameter

    Description

    identifier

    Script ID. Must be unique.

    name

    Script name.

    version

    Script version. Increment after each change, or the updated script will not take effect.

    scriptPath

    Script file path. Note:

    • The script must be placed in the /extension/local/script/ directory under the local storage path.

    • The JavaScript file name (for example, LLMChatAuditHandler.js) must match the identifier value.

    state

    Script state. enabled enables the script. disabled disables it.

    stage

    Processing stage. post means post-filter. pre means pre-filter. Default is pre.

    bizType

    Business scenario. completion applies to inline code generation. chat applies to AI chat.

Step 4: Upload the script

After local testing, upload the script:

  1. Go to the Qoder CN console. Choose Policy Management. Select the scenario where you want to enable the security filter.

  2. Select Custom Script as the filter option.

  3. Upload the compiled JavaScript file.

  4. Click Save Configuration. The configuration takes effect on the extension within about 5 minutes.

Custom Script API

Custom scripts support only one processing method:

  • No operation: Return the data unchanged and continue processing.

Interface definition
/**
 * Post-processing interface for Qoder CN
 * @param request User request
 * @param response Inference result from the LLM
 * @param SDKTool SDK utility class. Provides IDE and plugin information.
 * @returns Result after post-processing
 */
export interface RequestPostHandler {
  // Post-processing method
  handle: (request: RawRequest, response: AIResponse, SDKTool: Qoder CNSDKTool) => Promise<PostHandlerResponse>;
}
Input parameters
/**
 * Request object. Includes the action and raw data sent to the LLM.
 */
export interface RawRequest {
  // Unique identifier for the request. Used for tracing.
  action: ActionEnum;
  // Enum for the action that triggered the request.
  payload: ContentPayload;
  // Payload containing raw data.
  requestId: string;
}

/**
 * Inference result from the model
 */
export class InferredResult {
  // Text generated by the LLM
  text: string;
  constructor() {
    this.text = '';
  }
}

// Value type for ContentPayload.data
export type PayloadDataValueType = string | number | string[];
/**
 * Payload containing raw data sent to the LLM.
 */
export class ContentPayload {
  // Collection of data to process. Keys are defined in ContextValueKeyEnum.
  data: Map<PayloadDataKeyEnum, PayloadDataValueType>;
  // Context associated with the processing.
  associatedContexts: ContextItem[];

  constructor() {
    this.data = new Map<PayloadDataKeyEnum, PayloadDataValueType>();
    this.associatedContexts = [];
  }
}

/**
 * Keys for ContentPayload.data
 */
export enum PayloadDataKeyEnum {
  // Selected code snippet
  SELECTED_CODE ='lingma:code',
  // User input text
  USER_INPUT = 'lingma:text',
  // Error messages
  ERROR_MESSAGES = 'lingma:error_messages',
  // Terminal log output
  TERMINAL_CONTENT = 'lingma:terminal_content',
  // Code before cursor for code completion
  PREFIX_CODE = 'lingma:code_prefix',
  // Code after cursor for code completion
  SUFFIX_CODE = 'lingma:code_suffix',
  // Similar code snippets
  SIMILAR_CODE = 'lingma:similar_code',
  // File path for code completion
  FILE_PATH = 'lingma:file_path',
}

/**
 * Enum for request actions
 */
export enum ActionEnum {
    // Unit test
    GENERATE_TESTCASE           = 'GENERATE_TESTCASE',
    // Generate comments
    CODE_GENERATE_COMMENT       = 'CODE_GENERATE_COMMENT',
    // Explain code
    EXPLAIN_CODE                = 'EXPLAIN_CODE',
    // Optimize code
    OPTIMIZE_CODE               = 'OPTIMIZE_CODE',
    // Free input (direct text entry in the chat box)
    FREE_INPUT                  = 'FREE_INPUT',
    // Quick fix for code issues
    CODE_PROBLEM_SOLVE          = 'CODE_PROBLEM_SOLVE',
    // Generate shell commands
    TERMINAL_COMMAND_GENERATION = 'TERMINAL_COMMAND_GENERATION',
    // Fix terminal errors
    TERMINAL_EXPLAIN_FIX        = 'TERMINAL_EXPLAIN_FIX',
    // Code completion
    COMPLETION                  = 'COMPLETION',
}
Output parameters
/**
 * Post-processing result
 */
export class PostHandlerResponse {
  // Processing policy. Controls subsequent logic.
  handlePolicy: HandlePolicy;
  // Reason description
  reason?: string;
  // Processed inference result
  processedResult: InferredResult;
  constructor() {
    // Default values
    this.handlePolicy = HandlePolicy.NO_OPS;
    this.reason = '';
    this.processedResult = new InferredResult();
  }
}

/**
 * Encapsulates the LLM response
 */
export class AIResponse {
  // Inference result
  inferredResult: InferredResult;
  constructor() {
    this.inferredResult = new InferredResult();
  }
}

/**
 * Inference result from the model
 */
export class InferredResult {
  // Text generated by the LLM
  text: string;
  constructor() {
    this.text = '';
  }
}

/**
 * Processing policy enum (post-filters support only NO_OPS)
 */
export enum HandlePolicy {
  // Block the request
  BLOCK = 'BLOCK',
  // Filter the request and modify the payload
  FILTER = 'FILTER',
  // Take no action
  NO_OPS = 'NO_OPS',
}

Configure Knowledge Base Upload Filters (Enterprise Dedicated Edition only)

In the Enterprise Dedicated Edition, Qoder CN administrators and global administrators can configure knowledge base upload filters. After configuration, knowledge base files are reviewed before upload.

Configuration steps

Step 1: Enable and edit the knowledge base filter

  1. In the left navigation pane, click Policy Configuration. On the right, click the Knowledge Base Filter tab.

  2. In the Knowledge Base Filter configuration page, turn on the Enable or disable knowledge base upload pre-filter switch to edit parameters.

    URL

    Required

    Endpoint for your third-party scanning service. The service must accept POST requests.

    Token field name

    Required

    Name of the header field used to store the token.

    Secret key

    Required

    Secret key used to generate the access token. The token is placed in the specified header field to verify request legitimacy. See the Secure Token section.

Step 2: Test connectivity

  1. After entering the correct information, click Test Connection. The test succeeds if the third-party filter returns an HTTP 2xx status code.

  2. If another status code is returned, the test fails. Check your entries and try again.

Step 3: Save the knowledge base filter

Click Save Configuration to save your filter settings. The filter takes effect immediately after saving.

Third-party scanning service API

Your enterprise must provide a third-party scanning service that accepts POST requests. Only scanned content can be uploaded. The service interface must meet these requirements:

Request headers

Parameter name

Required

Description

Parameter examples

X-Auth-Raw

Yes

Authentication parameter. The parameter name matches the Token field name configured in the filter. The value is the token generated from the secret key using the encryption algorithm. See the Secure Token section for details.

6c3baa76c62550eab864e6f75c4bb

Content-Type

Yes

Media type for the request and response.

multipart/form-data

  • Secure Token: A secure signature designed by Alibaba Cloud to prevent malicious attackers from hijacking your cloud service permissions. Generating a token requires a secret key, current timestamp, additional data, and an encryption algorithm.

  • Token generation: When Qoder CN calls the third-party scanning service, it includes the secure token in the request header for authentication. Compute the token using these parameters:

    token = sha256Hex(method + url + timestamp + tokenSecret) + timestampHex

    method

    POST method.

    url

    URL of the scanning service endpoint you entered in the knowledge base filter configuration.

    timestamp

    Current timestamp.

    tokenSecret

    Secret key you entered in the knowledge base filter configuration.

    timestampHex

    Timestamp converted to hexadecimal.

  • Token verification: Your third-party scanning service can use the following code to validate the token.

    Important
    • Timestamp: Ensure client and server clocks are synchronized to avoid token validation failures due to clock skew.

    • Key management: Safeguard the tokenSecret. Do not share it with unauthorized users.

    • Expiration: Adjust the token lifetime based on your business needs. The example sets it to 60 seconds but you can change it.

    /*
     *  Method parameters:
     *  receivedHash: Received hash, which includes the timestamp.
     *  tokenSecret: Secret key used to generate the hash.
     *  url: Request URL.
     */
    public boolean validateAuthRaw(String receivedHash, String tokenSecret, String url) {
        final String method = "POST";
        
        // Extract timestamp from receivedHash
        String tsHex = receivedHash.substring(receivedHash.length() - 8);
        long tsSec = Long.parseLong(tsHex, 16);
        
        // Compare timestamps. Allow up to 60 seconds difference.
        long now = System.currentTimeMillis() / 1000L;
        if (Math.abs(now - tsSec) > 60) {
            return false; // Timestamp outside allowed range
        }
        
        // Build string to sign
        String plain = method + url + tsSec + tokenSecret;
        
        // Generate expected hash
        String expectedHash = org.apache.commons.codec.digest.DigestUtils.sha256Hex(plain);
        
        // Compare hashes
        return expectedHash.equals(receivedHash.substring(0, receivedHash.length() - 8));
    }

Request parameters

Parameter name

Type

Required

Description

Parameter Example

metadata

string

Yes

Business metadata. Content-Type: application/json

{"user": "user0000001",

"queryId": "cd2fd109-c4d4-489f-9b27-53752f7827d6"}

file

file

Yes

File to scan

Request example:

Content-Type: multipart/form-data; boundary=${bound}
--${bound}

Content-Disposition: form-data; name="metadata"

Content-Type: application/json
{
"user":"user0000001",
"queryID":"cd2fd109-c4d4-489f-9b27-53752f7827d6"
}

--${bound}
Content-Disposition: form-data; name="file"; filename="test-file.pdf"

Content-Type: application/pdf

%binary-file-content-here%

Response structure

The interface must return HTTP status code 200 and the following response body format.

Parameter name

Type

Required

Description

Parameter Example

forbidden

boolean

Yes

Security check result. true means the check failed.

false

errorMsg

string

No

Error message explaining why the check failed.

"File contains malicious content. Modify and re-upload."

queryId

string

No

Request ID. Must match the queryId field in the request metadata.

"cd2fd109-c4d4-489f-9b27-53752f7827d6"

user

string

No

User ID. Must match the user field in the request metadata.

"user0001"