Skip to content

Doc 97: Functional Packages Complete Decompilation

Overview

Complete bytecode-level decompilation and analysis of 8 functional packages containing ~58 classes total. All classes decompiled using javap -p -c with full bytecode disassembly.

Total classes analyzed: 58 (9 domain + 6 settings + 8 updater + 6 diff + 5 generate + 5 content + 8 language + 7 apm + 4 subpackage)


Package 1: com.aicode.domain (9 classes)

1.1 CommandCache

AspectDetail
TypeMutable data class (Lombok-style)
Fieldsboolean startSelected, int startSelectedStartOffset, boolean endSelected, int endSelectedStartOffset
MethodsGetters/setters, equals(), hashCode(), canEqual(), toString()
PurposeCaches command selection state (start/end offsets and selection flags) for inline chat or code complete

Key logic: Standard Lombok-generated equals/hashCode with prime multiplier 59. The canEqual() method confirms Lombok @EqualsAndHashCode.

1.2 GetTipsResult

AspectDetail
FieldsList<GetTipsResult$Tip> tips
Annotations@NotNull on constructor and getter
PurposeWraps server response for code completion tips

1.3 GetTipsResult$Tip (inner)

AspectDetail
Modifierfinal
FieldsString uuid, String text, Range range, String displayText, Position position
All fields@NotNull enforced
PurposeSingle completion suggestion with UUID, text, range, display text, and cursor position

1.4 LineInfo

AspectDetail
Modifierfinal
Fieldsint lineCount, int lineNumber, int lineStartOffset, int columnOffset, String line, int nextLineIndent
Key methodscreate(Document, int) - factory from IntelliJ Document; getLinePrefix(), getLineSuffix(), isBlankLine(), getWhitespaceBeforeCursor(), getLineEndOffset()
Static helpercalculateNextLineIndent(Document, int) - scans forward for next non-blank line's indent

Key logic: create() runs in a read action, catches Throwable and returns null on failure. calculateNextLineIndent() iterates forward through lines until finding a non-blank one, returning its whitespace prefix length or -1 if none found.

1.5 Position

AspectDetail
Fieldsint line, int character
Key methodsof(int, int) - static factory; Position(LineInfo) - from LineInfo; toOffset(String) - converts to char offset; getCursorPosition(Editor) - gets cursor position in read action
PurposeLSP-style Position (line, character)

Key logic: getCursorPosition() uses ApplicationManager.runReadAction() to safely access editor state. toOffset() delegates to StringUtil.lineColToOffset().

1.6 Range

AspectDetail
FieldsPosition start, Position end
Key methodsof(Position, Position) - static factory
PurposeLSP-style Range with start/end positions

1.7 Suggestion

AspectDetail
Modifierfinal
Fieldsint score, String type, String hash, CodeInlayList inlays
PurposeScored suggestion with type classification, content hash, and inlay presentation

1.8 VirtualFileUri

AspectDetail
Modifierfinal
FieldsString uri (private final)
StaticLogger LOG
Key methodsfrom(VirtualFile) - creates URI from IntelliJ VFS; from(VirtualFileSystem, String) - from filesystem + path
Private helpersprocessPath(String) - Windows path normalization; isNeedsPathPrefix(VirtualFileSystem) - Windows local FS detection; asPrefixedUri(String) - Windows UNC path handling

Key logic: Complex Windows path handling. On Windows, isNeedsPathPrefix() returns true for LocalFileSystem (but not TempFileSystem), adding a / prefix. processPath() converts // to \\ and $ to %24. asPrefixedUri() handles file://// and file:// prefix formats.

1.9 VirtualFileUri$TypeAdapter

AspectDetail
ImplementsGson JsonSerializer&lt;VirtualFileUri&gt;
Methodserialize() - outputs uri field as JsonPrimitive string
PurposeGson serialization adapter for VirtualFileUri

Package 2: com.aicode.settings (6 classes)

2.1 AICodeSettingsState -- PersistentStateComponent

AspectDetail
ImplementsPersistentStateComponent&lt;AICodeSettingsState&gt; (self-referencing)
ScopeApplication-level service
Total fields45+ public fields
PersistencegetState() returns this; loadState() uses XmlSerializerUtil.copyBean()

Complete field inventory:

CategoryFields
CoreautoTrigger (true), tipType (INTELLIGENT_MODE), sendKey (ENTER_KEY), modelCode (""), inlineChatModelCode (""), triggerTime (200ms)
URLsloginUrl, feedbackUrl, maintainRepoUrl, codeSearchServerUrl, officialWebsiteUrl, codeKnowledgeWebUrl, userCenterWebUrl
IdentityenterpriseId, enterpriseName, userId, userName
UpdateisUpdater (false), openAutoUpdate (true)
Java TesttestFramework (JUNIT_FOUR), mockFramework (POWER_MOCK), modifyTestFrame (false), modifyTestFramenNum (0)
Python TestpyTestFramework (UNITTEST), pyMockFramework (UNITTESTMOCK), pyModifyTestFrame (false), pyModifyTestFramenNum (0)
ModelsmodelList (HashMap), modelInfoList, inlineCompletionInputStyle (DISPOSABLE), defaultLanguage (auto), languages (ArrayList)
CompletioncodeCompleteDisableLang (["txt","md"]), enableCodeComplete (false), enableCodeDebug (true), enableCodeEnhance (false), openCodeEnhance (true), streamOutputConfig (false)
Line ToolslineToolsType (ICON), lineToolsPermissionDocComments (true), lineToolsPermissionLineComments (true), lineToolsPermissionComments (true), lineToolsPermissionFunctionSplit (true), lineToolsPermissionCodeOptimization (true), lineToolsPermissionUnitTesting (true)
Feature FlagsopenFunctionSplit (true), openCodeOptimization (true), openIFlyTest (true), openInlineChat (true), openIFlyDBA (true), openIFlyOps (true), openIFlyPm (true)
APMapmEnable (null/Boolean), apmUrl
Otherpermissions (LinkedHashSet), generateUnitTestFile, unitRequestInterval (8), showSaasQrCode (false), ignoreGitAuth (false), ignoreVersion

Key methods:

  • clear() - resets user identity, URLs, model list, permissions; calls PluginStartupActivity.setApiKey("")
  • setUnitRequestInterval(int) - adaptive: newInterval = Math.min(5, input) + current) / 2 (moving average with floor of 5)
  • getUnitRequestInterval() - enforces minimum of 5

2.2 AICodeRequestSettings -- PersistentStateComponent

AspectDetail
ImplementsPersistentStateComponent&lt;CodeGenerateRequestState&gt;
ScopeApplication-level service
Key methodssettings() - static accessor; getState() / loadState() / noStateLoaded() (synchronized)
State classCodeGenerateRequestState

2.3 CodeGenerateRequestState

AspectDetail
FieldsColor inlayTextColor (null), boolean showIdeCodeTips (false), transient boolean internalDisableHttpCache (false), boolean requestLimitNotificationShown (false)
ColorSerialized via ColorConverter
PurposeUI/visual settings for code generation requests

2.4 BatchUnitTestSettingsState -- PersistentStateComponent

AspectDetail
ImplementsPersistentStateComponent&lt;BatchUnitTestSettingsState&gt; (self-referencing)
FieldstestFramework (JUNIT_FOUR), mockFramework (POWER_MOCK), testGenerationProcess (GENERATION), enabledGenerateByTemplate (DISABLED), testPrivate (false), duplicateRule (COEXIST), testModuleDirectory (null), savePath (true), batchTestUnitLimt (FIVE)
PurposeBatch unit test generation configuration

2.5 UnitTestSettingsState -- PersistentStateComponent

AspectDetail
ImplementsPersistentStateComponent&lt;UnitTestSettingsState&gt; (self-referencing)
FieldstestFramework (JUNIT_FOUR), mockFramework (POWER_MOCK), enabledGenerateByTemplate (DISABLED), testPrivate (false), testClasPath (""), savePath (false)
PurposeSingle-file unit test generation configuration

2.6 ColorConverter

AspectDetail
ExtendsConverter&lt;Color&gt; (IntelliJ XML serializer)
MethodsfromString(String) - hex to Color via ColorUtil.fromHex(); toString(Color) - Color to HTML hex via ColorUtil.toHtmlColor()
Error handlingfromString() catches Exception and returns null

Package 3: com.aicode.updater (8 classes)

3.1 PluginUpdater

AspectDetail
Source filelb (obfuscated)
Static fieldsLogger logger, AtomicReference&lt;String&gt; enum (tracks last update version)
Key methodscheckUpdate(Project, JsonObject) - synchronized; notification(Project, String); doUpdate(Project, String, String, String, String)

checkUpdate() flow:

  1. Skip if SaaS scene
  2. Parse JsonObject for updateInfo -> LoginInfo DTO
  3. Extract current, update, file, md5, name from LoginInfo
  4. If any blank, return
  5. If current != update, invoke doUpdate() on EDT

doUpdate() flow:

  1. Check AtomicReference to avoid duplicate notifications for same version
  2. Copy plugin JAR from source file to PathManager.getPluginTempPath() using cn.hutool.core.io.FileUtil.copy()
  3. Call disableOrEnablePlugin() to disable current plugin
  4. Find enabled plugin descriptor
  5. Call installAfterRestart() with plugin descriptor, new path, old path
  6. If isOccurred() (first install), update InstalledPluginsState

CRITICAL SECURITY ISSUE: MD5 not verified! The md5 field is extracted from LoginInfo but never used in doUpdate(). The downloaded plugin JAR is copied and installed without any integrity verification. This allows:

  • Man-in-the-middle attacks to inject malicious plugin code
  • Corrupted downloads to be installed
  • Supply chain attacks if the update server is compromised

3.2 PluginUpdater$E (Restart Action)

AspectDetail
ExtendsNotificationAction
ActionOn actionPerformed(), calls Application.restart() via invokeLater()
Purpose"Restart" button in update notification

3.3 PluginUpdater$m (Dismiss Action)

AspectDetail
ExtendsNotificationAction
ActionOn actionPerformed(), calls notification.hideBalloon()
Purpose"Dismiss" button in update notification

3.4 PluginUpdaterCheckService

AspectDetail
Source filehb (obfuscated)
Static fieldsvolatile boolean final (checking flag), volatile boolean try (installing flag), Object float (lock), String byte (last version), Logger enum
Key methodsscheduleRepeatedUpdateCheck(Project) - schedules every 24 hours; queueUpdateCheck(Project) - synchronized check; O(ProgressIndicator) - find updates; N(Collection) - filter AICode plugin; t(Project, PluginDownloader, ProgressIndicator) - install update

Update check flow:

  1. scheduleRepeatedUpdateCheck() uses AppExecutorUtil with 24-hour fixed delay
  2. queueUpdateCheck() synchronized on lock object, creates CheckUpdatesTask if not already checking
  3. O() dispatches to UpdaterChecker2021_1 or UpdaterCheckerFrom2021_2 based on IDE build baseline version (<=211 vs >211)
  4. N() filters for AICode plugin by ID
  5. t() uses reflection to call updateAndInstall() on PluginDownloader (accessing internal IntelliJ API)

3.5 PluginUpdaterCheckService$CheckUpdatesTask

AspectDetail
ExtendsTask.Backgroundable
Run logicCalls O() to find updates, N() to filter, then t() to install if new version found
Error handlingSets final flag to false on cancel/error

3.6 PluginUpdaterCheckService$k

AspectDetail
ExtendsTask.Backgroundable
FieldsProject byte, PluginDownloader enum
PurposeBackground task for downloading and installing a specific plugin update

3.7 UpdaterChecker2021_1

AspectDetail
PurposeUpdate checker for IntelliJ 2021.1 and earlier
MethodfindAvailableUpdates() uses reflection to call UpdateChecker.checkForUpdates() then getAvailableUpdates()
Error handlingCatches NoSuchMethodException, InvocationTargetException, IllegalAccessException; returns empty list on failure

3.8 UpdaterCheckerFrom2021_2

AspectDetail
PurposeUpdate checker for IntelliJ 2021.2+
MethodfindAvailableUpdates() uses reflection to call UpdateChecker.checkForUpdatesAndLoadPluginDescriptors() then getAvailableUpdates() with different method chain
Error handlingSame as UpdaterChecker2021_1

Both updaters use reflection because UpdateChecker is an internal IntelliJ API that changed between versions. The obfuscated string constants are method names decoded at runtime.


Package 4: com.aicode.diff (6 classes)

4.1 CloudDiffUtil

AspectDetail
Static fields5 Key&lt;String&gt; constants: DIFF_FILENAME, DIFF_FILEPATH_LEFT, DIFF_FILEPATH_RIGHT, DIFF_FILE_UNIQUE_ID, DIFF_SUGGEST_CODE
PurposeUserData keys for passing diff information through IntelliJ's diff framework
ObfuscationKey names are H()-deobfuscated at class initialization

4.2 DiffDialog

AspectDetail
ExtendsDialogWrapper
FieldsProject byte, SimpleDiffRequest enum (obfuscated names)
Key methodscreateCenterPanel() - creates diff panel; doOKAction() - applies right-side content to left file; createActions() - OK (Apply) and Cancel buttons
Apply logicReads left VirtualFile content, removes CR (char 13), writes to right file via WriteCommandAction
TrackingCalls EditorManagerServiceImpl.acceptCount() with CodeCollectEnum.COMPARE

4.3 DiffService

AspectDetail
Static fieldsKey&lt;VirtualFile&gt; DIFF_FILEPATH_LEFT/RIGHT, String tempDirectoryName, Logger
Key methodsreplaceTextInVirtualFile() - write command to replace text range; closeDiffViewIfAlreadyOpened() - iterates editors to find and close existing diff; openDiff() - creates and shows diff dialog
PurposeCore diff service managing file comparison and content replacement

4.4 FileInfo

AspectDetail
Fieldsboolean byte (couldFile), VirtualFile enum (vf)
Static methodH(Object) - H-function deobfuscation (XOR-based string decoder using caller class+method as key)
PurposeFile info wrapper with cloud file flag

The H() method is a critical deobfuscation function used throughout the codebase. It:

  1. Gets caller class name + method name via LinkageError().getStackTrace()[1]
  2. XORs input string characters with key derived from the caller name
  3. Returns decoded string

4.5 FileService

AspectDetail
Key methodsreplaceContentInFile(String, String, String, String, int, int) - line-based file content replacement; replaceContentInFile(String, String) - full file replacement; deleteFile(File); addWriteSpace() - indentation adjustment
Line endingHandles \r\n, \n, \r line separators with H()-decoded patterns
PurposeLow-level file I/O for diff operations

4.6 GenericUtils

AspectDetail
Static methodsH(Object) - H-function deobfuscation; generateRandomInt(int, int); isCloudFile(VirtualFile); getVersionedFileName(String, String); getClodFileMeta(String)
Cloud fileisCloudFile() checks if path metadata has 6 segments (split by O-decoded separator)
PurposeUtility class with deobfuscation and cloud file detection

Package 5: com.aicode.generate (5 classes)

5.1 SimpleCodeTipCache

AspectDetail
ImplementsTipCache
FieldsString case (latest prefix), ReadWriteLock final, Logger try, boolean float (enabled), LinkedHashMap<Z, List&lt;CodeTip&gt;> byte (cache map), String enum (current file)
Key methodsisLatestPrefix(String) - checks if prefix matches latest; mF(String) - SHA-256 hash of prefix via DigestUtil.sha256Hex()
Cache keySimpleCodeTipCache$Z - contains boolean byte (isPartial) + String enum (hashed prefix)
Cache mapSimpleCodeTipCache$Y extends LinkedHashMap with LRU eviction (removeEldestEntry)
Thread safetyUses ReadWriteLock for concurrent access

Cache strategy:

  • Key = (isPartial, SHA-256(prefix))
  • LRU eviction when map size exceeds configured capacity
  • SHA-256 hashing prevents cache key collision on long prefixes
  • ReadWriteLock allows concurrent reads, exclusive writes

5.2 SimpleCodeTipCache$Z (Cache Key)

AspectDetail
Modifierfinal
Fieldsboolean byte (isPartial), String enum (hashed prefix)
Custom equals()Compares both isPartial flag and prefix string

5.3 SimpleCodeTipCache$Y (Cache Map)

AspectDetail
ExtendsLinkedHashMap<Z, List&lt;CodeTip&gt;>
Fieldint byte (max capacity)
removeEldestEntry()Returns true when size() > capacity - implements LRU eviction

5.4 DefaultInlayList

AspectDetail
ImplementsCodeInlayList
FieldsList&lt;CodeEditorInlay&gt; final, TextRange try, CodeTip float, String byte (replacementText), boolean enum (removeBlank)
PurposeDefault implementation of inlay presentation list for code tips

5.5 CodeTipUtil

AspectDetail
Static fieldLogger enum
PurposeUtility for code tip operations (heavily obfuscated)

Package 6: com.aicode.content (5 classes in util/ and util/file/)

6.1 EditorUtils (content/util)

AspectDetail
Key methodcreateEditor(Project, String, String) - creates read-only editor with LightVirtualFile, disables highlighting
PurposeCreates temporary editor instances for preview/display

6.2 OverlayUtils (content/util)

AspectDetail
Key methodsshowInfoBalloon(String, Point) - shows info notification; H(Object) - H-function deobfuscation
PurposeUI overlay utilities for balloon notifications

6.3 FileUtils (content/util/file)

AspectDetail
Key methodsgetEditorFile(Editor) - gets VirtualFile from editor; createFile(String, String, String) - creates file with content; tryCreateDirectory(String) - mkdirs
PurposeFile I/O utilities for content operations

6.4 FileExtensionLanguageDetails (content/util/file)

AspectDetail
FieldsString byte (extension), String enum (language)
StaticH(Object) - H-function deobfuscation
PurposeMaps file extensions to language identifiers

6.5 LanguageFileExtensionDetails (content/util/file)

AspectDetail
FieldsString float (type), List&lt;String&gt; byte (extensions), String enum (name)
PurposeMaps language names to supported file extensions

Package 7: com.aicode.language (8 classes)

7.1 LanguageMap

AspectDetail
Modifierfinal
Static fieldMap<String, String> enum (unmodifiable, backed by ConcurrentHashMap)
Key methodgetId(Language) - maps IntelliJ Language ID to VS Code language ID
PurposeIntelliJ-to-VSCode language identifier mapping

7.2 LanguageMap$s

AspectDetail
ExtendsConcurrentHashMap<String, String>
PurposeThread-safe language mapping storage

7.3 AICodeExtendedLanguageSupport

AspectDetail
ImplementsLanguageInfoSupport (extension point)
Static fieldMap<W, String> enum - single mapping entry (obfuscated keys)
Key methodfindVSCodeLanguageMapping(PsiFile) - looks up language+extension in map
PurposeExtended language support beyond built-in mappings

7.4 AICodeExtendedLanguageSupport$W

AspectDetail
Modifierfinal
FieldsString byte (language ID), String enum (extension)
PurposeComposite key for language+extension lookup

7.5 AICodeLanguageInfo

AspectDetail
Modifierfinal
FieldsString byte (VS Code ID), Language enum (IntelliJ Language)
PurposeLanguage info pairing IntelliJ Language with VS Code identifier

7.6 CodeLanguageInfoSupport

AspectDetail
ImplementsLanguageInfoSupport
PurposeBuilt-in language support implementation (heavily obfuscated)

7.7 CommonLanguageSupport

AspectDetail
Modifierfinal
Static fieldPattern enum - compiled regex for line position validation
Key methodisValidMiddleOfTheLinePosition(String) - checks if cursor is at valid mid-line position
PurposeCommon language-agnostic position validation

7.8 LanguageInfoManager

AspectDetail
Modifierfinal
Static fieldKey&lt;AICodeLanguageInfo&gt; enum - PsiFile user data cache key
Key methodsfindLanguageMapping(PsiFile) - finds language mapping with caching; findFallback(VirtualFile) - fallback when no mapping found
CachingResults cached in PsiFile's UserData
Extension pointUses LanguageInfoSupport.EP extension point

Package 8: com.aicode.apm (7 classes)

8.1 OpenTelemetryConfig

AspectDetail
Static fieldslong final (export timeout), int try (schedule delay), Logger float, int byte (max queue), int enum (max batch)
Key methodsinit(String) - initializes OpenTelemetry SDK; AE() - builds Resource; td(String) - creates BatchSpanProcessor; jE(String) - creates OTLP HTTP exporter; IF(TrustManager[]) - creates SSLContext; xE() - creates TrustManager array; VD() - creates RetryPolicy

init() flow:

  1. Build SdkTracerProvider with traceIdRatioBased(1.0) sampler (100% sampling)
  2. Add BatchSpanProcessor with OTLP HTTP exporter
  3. Set Resource with service name, system username, IDEA version, plugin version
  4. Build OpenTelemetrySdk with W3C trace context + W3C baggage propagators
  5. On exception, log and return null

BatchSpanProcessor configuration:

  • Export timeout: 30000ms
  • Schedule delay: 5000ms
  • Max queue size: 2048
  • Max export batch size: 512

RetryPolicy:

  • Max attempts: 2
  • Initial backoff: 1s
  • Max backoff: 5s
  • Backoff multiplier: 1.5

8.2 OpenTelemetryConfig$La -- SECURITY: Trust-all X509TrustManager

AspectDetail
ImplementsX509TrustManager
checkClientTrusted()EMPTY - accepts all certificates
checkServerTrusted()EMPTY - accepts all certificates
getAcceptedIssuers()Returns empty X509Certificate[]

CRITICAL SECURITY ISSUE: This TrustManager completely disables SSL certificate verification. Any HTTPS connection made through this SSL context will accept:

  • Self-signed certificates
  • Expired certificates
  • Certificates for wrong hostnames
  • Man-in-the-middle intercepted connections

This affects all OpenTelemetry APM trace exports, meaning an attacker could:

  1. Intercept and read all APM telemetry data
  2. Inject fake telemetry data
  3. Perform MITM attacks on the APM endpoint

8.3 OpenTelemetryConfig$ca -- Custom ProxySelector

AspectDetail
ExtendsProxySelector
select(URI)Uses reflection to access IntelliJ's ProxySettings internal fields
LogicIf IntelliJ HTTP proxy is enabled and URI scheme is "https", creates Proxy(HTTP, InetSocketAddress(host, port))
ReflectionAccesses isHttpProxyEnabled, httpProxyHost, httpProxyPort fields via setAccessible(true)

Security concern: Uses reflection with setAccessible(true) to bypass access controls on IntelliJ's internal proxy settings class.

8.4 OpenTelemetryService

AspectDetail
Static fieldLogger enum
Instance fieldSpan parentSpan
Key methodsgetInstance() - application service; handApmConfig(JsonObject) - processes APM config from server; kd(String) - health check via OkHttp

handApmConfig() flow:

  1. Get current apmUrl and apmEnable from AICodeSettingsState
  2. If JsonObject provided, extract new apmUrl and apmEnable from it
  3. If URL is blank or doesn't start with "https", call GlobalOpenTelemetry.resetForTest() (disable APM)
  4. If apmEnable is true and URL is valid, call init() to initialize OpenTelemetry
  5. If apmEnable is false, reset APM

kd() method: Makes HTTP GET request to APM URL using OkHttp to verify connectivity. Returns true if response has non-blank message.

8.5 OpenTelemetryUtil

AspectDetail
Key methodsbuildWithParent(Span, TracerEnum, String) - creates child span; buildWithCommand(String, String) - creates CLIENT span; buildWithTracer(TracerEnum, String) - creates span from tracer; eF() - internal span builder; H(Object) - H-function deobfuscation

Span creation:

  • Uses GlobalOpenTelemetry.getTracer() with tracer name from TracerEnum
  • Supports parent context propagation via Context.current().with(parentSpan)
  • Default SpanKind.INTERNAL for parent spans, SpanKind.CLIENT for command/tracer spans

8.6 SpanAttrEnum (apm/enums)

AspectDetail
ConstantsSYSTEM_USERNAME, IDEA_VERSION, PLUGIN_VERSION (observed in Resource builder)
PurposeEnum for OpenTelemetry span attribute keys

8.7 TracerEnum (apm/enums)

AspectDetail
PurposeEnum for OpenTelemetry tracer names
UsagePassed to OpenTelemetryUtil.buildWithParent() and buildWithTracer()

Analysis Section

A. Configuration Persistence Mechanism

4 PersistentStateComponent implementations:

ComponentState TypeScopeStorage
AICodeSettingsStateSelf (AICodeSettingsState)ApplicationXML via XmlSerializerUtil.copyBean()
AICodeRequestSettingsCodeGenerateRequestStateApplicationXML (synchronized access)
BatchUnitTestSettingsStateSelfApplicationXML via XmlSerializerUtil.copyBean()
UnitTestSettingsStateSelfApplicationXML via XmlSerializerUtil.copyBean()

Persistence pattern:

  • All use XmlSerializerUtil.copyBean() in loadState() for XML deserialization
  • AICodeRequestSettings additionally implements noStateLoaded() to create default state
  • AICodeRequestSettings.getState() is synchronized for thread safety
  • AICodeSettingsState.getState() returns this (self-persisting pattern)
  • All accessed via ApplicationManager.getApplication().getService() (application-level services)

AICodeSettingsState is the central configuration hub with 45+ fields covering all plugin functionality.

B. Auto-Update Mechanism

Update flow:

PluginUpdaterCheckService.scheduleRepeatedUpdateCheck()
  -> Every 24 hours via AppExecutorUtil
  -> queueUpdateCheck() [synchronized]
    -> CheckUpdatesTask (Backgroundable)
      -> O() findAvailableUpdates()
        -> UpdaterChecker2021_1 or UpdaterCheckerFrom2021_2 [reflection-based]
      -> N() filter for AICode plugin
      -> t() install update [reflection to call updateAndInstall()]

Server-initiated update:

PluginUpdater.checkUpdate(Project, JsonObject)
  -> Parse LoginInfo (current, update, file, md5, name)
  -> If current != update, doUpdate() on EDT
    -> Copy JAR to plugin temp path
    -> disableOrEnablePlugin() to disable current
    -> installAfterRestart() with new path

Key observations:

  1. Two update paths: scheduled (every 24h) and server-push (via login response)
  2. Both use IntelliJ's internal PluginDownloader API via reflection
  3. IDE version branching: UpdaterChecker2021_1 for <=2021.1, UpdaterCheckerFrom2021_2 for >=2021.2
  4. AtomicReference&lt;String&gt; prevents duplicate notifications
  5. Update notification has "Restart" and "Dismiss" actions

C. APM/OpenTelemetry Integration

Architecture:

OpenTelemetryService (singleton, application service)
  -> handApmConfig(JsonObject) - receives config from server
  -> OpenTelemetryConfig.init(apmUrl)
    -> SdkTracerProvider with 100% sampling
    -> BatchSpanProcessor (5s delay, 2048 queue, 512 batch)
    -> OtlpHttpSpanExporter (gzip, retry policy)
    -> SSLContext with Trust-all TrustManager [INSECURE]
    -> ProxySelector from IntelliJ proxy settings [reflection]
    -> Resource with service/IDE/plugin metadata
  -> OpenTelemetryUtil - span creation utilities
    -> buildWithParent(), buildWithCommand(), buildWithTracer()
    -> W3C Trace Context + W3C Baggage propagation

Configuration flow:

  1. Server sends APM config (URL + enable flag) in login response
  2. OpenTelemetryService.handApmConfig() processes config
  3. If enabled and URL starts with "https", initializes SDK
  4. If disabled or invalid URL, resets via GlobalOpenTelemetry.resetForTest()
  5. Health check via kd() method using OkHttp GET

D. Security Issues Summary

#SeverityComponentIssueImpact
1CRITICALOpenTelemetryConfig$LaTrust-all X509TrustManagerAll SSL certificate verification disabled for APM connections; enables MITM attacks
2HIGHPluginUpdater.doUpdate()MD5 not verified on downloaded pluginDownloaded plugin JAR installed without integrity check; enables supply chain attacks
3MEDIUMOpenTelemetryConfig$caReflection bypass of access controlssetAccessible(true) on IntelliJ internal proxy fields; could break with IDE updates
4MEDIUMUpdaterChecker2021_1/From2021_2Reflection to access internal UpdateChecker APIFragile dependency on IntelliJ internals; different method chains per IDE version
5LOWAICodeSettingsState.clear()Calls PluginStartupActivity.setApiKey("")API key clearing coupled with settings reset; potential side effects
6LOWOpenTelemetryConfig.init()100% trace sampling (traceIdRatioBased(1.0))All requests traced; potential performance overhead and data volume
7INFOSimpleCodeTipCacheSHA-256 cache key hashingCache keys are SHA-256 hashes of prefixes; prevents collision but adds overhead

E. String Obfuscation Pattern

Multiple classes implement the H(Object) static method for string deobfuscation:

ClassPattern
FileInfo.H()XOR-based with caller class+method name as key
GenericUtils.H()Same XOR pattern
OverlayUtils.H()Same XOR pattern
FileExtensionLanguageDetails.H()Same XOR pattern
LanguageFileExtensionDetails.H()Same XOR pattern
FileService.H()Same XOR pattern
OpenTelemetryUtil.H()Same XOR pattern

Common pattern:

  1. Get caller class name + method name via new LinkageError().getStackTrace()[1]
  2. Concatenate to form XOR key
  3. Iterate input string, XOR each character with corresponding key character
  4. Return decoded string

This obfuscation is applied to all string constants in the updater, diff, content, language, and APM packages.

F. Class Count Summary

PackageClassesInner ClassesTotal
domain72 (Tip, TypeAdapter)9
settings606
updater44 (E, m, CheckUpdatesTask, k)8
diff606
generate32 (Y, Z)5
content/util202
content/util/file303
language62 (W, s)8
apm32 (La, ca)5
apm/enums202
Total441458

本项目仅供学习研究,逆向分析内容归原厂商所有。