mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 11:53:49 +07:00
[settings-sync] IJPL-176491 Limit available settings providers for settings sync to IDE vendor
(cherry picked from commit e55e88e2f8606860c6696afaacf51e17b7ca6bba) IJ-CR-173221 GitOrigin-RevId: e976a9402db73ef8eaa7307ed774bb3c561be21e
This commit is contained in:
committed by
intellij-monorepo-bot
parent
1a5ded5816
commit
b5254cbf09
@@ -11,6 +11,7 @@ import com.intellij.ide.plugins.PluginManagerCore.getPluginSet
|
||||
import com.intellij.ide.plugins.PluginManagerCore.isDisabled
|
||||
import com.intellij.ide.plugins.PluginManagerCore.loadedPlugins
|
||||
import com.intellij.ide.plugins.PluginManagerCore.processAllNonOptionalDependencies
|
||||
import com.intellij.ide.plugins.cl.PluginAwareClassLoader
|
||||
import com.intellij.ide.plugins.cl.PluginClassLoader
|
||||
import com.intellij.idea.AppMode
|
||||
import com.intellij.openapi.application.PathManager
|
||||
@@ -20,6 +21,7 @@ import com.intellij.openapi.extensions.PluginDescriptor
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.BuildNumber
|
||||
import com.intellij.openapi.util.IntellijInternalApi
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.openapi.util.text.HtmlChunk
|
||||
import com.intellij.ui.IconManager
|
||||
@@ -213,11 +215,17 @@ object PluginManagerCore {
|
||||
fun isPlatformClass(fqn: String): Boolean =
|
||||
fqn.startsWith("java.") || fqn.startsWith("javax.") || fqn.startsWith("kotlin.") || fqn.startsWith("groovy.")
|
||||
|
||||
private fun isVendorItemTrusted(vendorItem: String): Boolean =
|
||||
if (vendorItem.isEmpty()) false
|
||||
else isVendorJetBrains(vendorItem) ||
|
||||
vendorItem == ApplicationInfoImpl.getShadowInstance().companyName ||
|
||||
vendorItem == ApplicationInfoImpl.getShadowInstance().shortCompanyName
|
||||
@ApiStatus.Internal
|
||||
fun isVendorItemTrusted(vendorItem: String): Boolean {
|
||||
return if (vendorItem.isBlank()) {
|
||||
false
|
||||
}
|
||||
else {
|
||||
isVendorJetBrains(vendorItem)
|
||||
|| vendorItem == ApplicationInfoImpl.getShadowInstance().companyName
|
||||
|| vendorItem == ApplicationInfoImpl.getShadowInstance().shortCompanyName
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isVendorTrusted(vendor: String): Boolean =
|
||||
@@ -993,7 +1001,7 @@ fun pluginRequiresUltimatePluginButItsDisabled(plugin: PluginId, pluginMap: Map<
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun pluginRequiresUltimatePlugin(plugin: PluginId,
|
||||
fun pluginRequiresUltimatePlugin(plugin: PluginId,
|
||||
pluginMap: Map<PluginId, IdeaPluginDescriptorImpl>,
|
||||
contentModuleMap: Map<String, ContentModuleDescriptor>,
|
||||
): Boolean {
|
||||
@@ -1014,3 +1022,21 @@ fun pluginRequiresUltimatePlugin(rootDescriptor: IdeaPluginDescriptorImpl,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
@IntellijInternalApi
|
||||
fun isPlatformOrJetBrainsBundled(aClass: Class<*>): Boolean {
|
||||
val classLoader = aClass.classLoader
|
||||
when {
|
||||
classLoader is PluginAwareClassLoader -> {
|
||||
val plugin = classLoader.pluginDescriptor
|
||||
return plugin.isBundled && PluginManagerCore.isDevelopedByJetBrains(plugin)
|
||||
}
|
||||
PluginManagerCore.isRunningFromSources() -> {
|
||||
return true
|
||||
}
|
||||
else -> {
|
||||
return PluginUtils.getPluginDescriptorIfIdeaClassLoaderIsUsed(aClass) == null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ f:com.intellij.openapi.extensions.DefaultPluginDescriptor
|
||||
- com.intellij.openapi.extensions.PluginDescriptor
|
||||
- <init>(com.intellij.openapi.extensions.PluginId):V
|
||||
- <init>(com.intellij.openapi.extensions.PluginId,java.lang.ClassLoader):V
|
||||
- <init>(com.intellij.openapi.extensions.PluginId,java.lang.ClassLoader,java.lang.String):V
|
||||
- <init>(java.lang.String):V
|
||||
- getCategory():java.lang.String
|
||||
- getChangeNotes():java.lang.String
|
||||
|
||||
@@ -10,20 +10,24 @@ import java.util.Date;
|
||||
public final class DefaultPluginDescriptor implements PluginDescriptor {
|
||||
private final @NotNull PluginId myPluginId;
|
||||
private final ClassLoader myPluginClassLoader;
|
||||
private final String myVendor;
|
||||
|
||||
public DefaultPluginDescriptor(@NotNull String pluginId) {
|
||||
myPluginId = PluginId.getId(pluginId);
|
||||
myPluginClassLoader = null;
|
||||
this(PluginId.getId(pluginId), null);
|
||||
}
|
||||
|
||||
public DefaultPluginDescriptor(@NotNull PluginId pluginId) {
|
||||
myPluginId = pluginId;
|
||||
myPluginClassLoader = null;
|
||||
this(pluginId, null);
|
||||
}
|
||||
|
||||
public DefaultPluginDescriptor(@NotNull PluginId pluginId, @Nullable ClassLoader pluginClassLoader) {
|
||||
this(pluginId, pluginClassLoader, null);
|
||||
}
|
||||
|
||||
public DefaultPluginDescriptor(@NotNull PluginId pluginId, @Nullable ClassLoader pluginClassLoader, @Nullable String vendor) {
|
||||
myPluginId = pluginId;
|
||||
myPluginClassLoader = pluginClassLoader;
|
||||
myVendor = vendor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,7 +82,7 @@ public final class DefaultPluginDescriptor implements PluginDescriptor {
|
||||
|
||||
@Override
|
||||
public @Nullable String getVendor() {
|
||||
return null;
|
||||
return myVendor;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -46,7 +46,10 @@
|
||||
<extensionPoints>
|
||||
<extensionPoint qualifiedName="com.intellij.settingsSyncMigration" interface="com.intellij.settingsSync.core.SettingsSyncMigration" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.settingsSync.settingsProvider" interface="com.intellij.settingsSync.core.SettingsProvider" dynamic="true" />
|
||||
<extensionPoint qualifiedName="com.intellij.settingsSync.communicatorProvider" interface="com.intellij.settingsSync.core.communicator.SettingsSyncCommunicatorProvider" dynamic="true"/>
|
||||
<extensionPoint qualifiedName="com.intellij.settingsSync.communicatorProvider"
|
||||
beanClass="com.intellij.settingsSync.core.communicator.SettingsSyncCommunicatorBean" dynamic="true">
|
||||
<with attribute="implementation" implements="com.intellij.settingsSync.core.communicator.SettingsSyncCommunicatorProvider"/>
|
||||
</extensionPoint>
|
||||
</extensionPoints>
|
||||
|
||||
<actions resource-bundle="messages.SettingsSyncBundle">
|
||||
|
||||
@@ -90,7 +90,7 @@ plugins.bundled=Bundled plugins
|
||||
subcategory.config.link=Configure
|
||||
#temporary message
|
||||
settings.jba.plugin.required.text=Please download JetBrains "Backup and Sync" plugin from the Plugins page
|
||||
settings.jba.plugin.required.title=Plugin download required
|
||||
settings.jba.plugin.required.title=Plugin Download Required
|
||||
settings.jba.plugin.download=Downloading plugins
|
||||
|
||||
settings.category.ui.editor.font=Editor font
|
||||
|
||||
@@ -6,7 +6,7 @@ import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
/**
|
||||
* Allows to store custom settings in the settings sync, if these settings can't be collected and applied via the standard
|
||||
* Allows storing custom settings in the settings sync, if these settings can't be collected and applied via the standard
|
||||
* [PersistentStateComponent] mechanism.
|
||||
*
|
||||
* @param T the structure class holding the settings.
|
||||
@@ -16,7 +16,8 @@ import org.jetbrains.annotations.ApiStatus
|
||||
interface SettingsProvider<T: Any> {
|
||||
|
||||
companion object {
|
||||
val SETTINGS_PROVIDER_EP = ExtensionPointName.create<SettingsProvider<*>>("com.intellij.settingsSync.settingsProvider")
|
||||
val SETTINGS_PROVIDER_EP: ExtensionPointName<SettingsProvider<*>> =
|
||||
ExtensionPointName.create("com.intellij.settingsSync.settingsProvider")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,7 +65,7 @@ interface SettingsProvider<T: Any> {
|
||||
*
|
||||
* @param newer The state of the settings which was made later.
|
||||
* Usually, if there is a real conflict in the settings between the local and the cloud modifications (when the same property is set
|
||||
* to different values), then the newer version should be performed, because that value was set by the user more recently.
|
||||
* to different values), then the newer version should be performed. The user set that value more recently.
|
||||
*
|
||||
* @return the resulting state which will be used as the conflict resolution and will be recorded to the settings sync and propagated
|
||||
* both to the local IDE and to the cloud (and then to other machines).
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
package com.intellij.settingsSync.core.auth
|
||||
|
||||
import com.intellij.settingsSync.core.SettingsSyncStatusTracker
|
||||
import com.intellij.settingsSync.core.communicator.SettingsSyncUserData
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.Nls
|
||||
import java.awt.Component
|
||||
import javax.swing.Icon
|
||||
|
||||
/**
|
||||
* This is an internal extension that requires an explicit license agreement with JetBrains s.r.o. for plugins.
|
||||
* Only IDE-bundled plugins are allowed to implement it.
|
||||
*
|
||||
* Contact https://platform.jetbrains.com/ for details.
|
||||
* You may not use this extension until it is unlocked in the platform for your plugin.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
interface SettingsSyncAuthService {
|
||||
/**
|
||||
* short, self-explanatory and unique code name of the provider. May or may not match the
|
||||
* @see com.intellij.settingsSync.communicator.SettingsSyncCommunicatorProvider#getProviderCode()
|
||||
* short, self-explanatory and unique code name of the provider. May or may not match the provider code.
|
||||
* @see com.intellij.settingsSync.core.communicator.SettingsSyncCommunicatorProvider#getProviderCode()
|
||||
*/
|
||||
val providerCode: String
|
||||
|
||||
@@ -26,7 +34,7 @@ interface SettingsSyncAuthService {
|
||||
/**
|
||||
* Provides a function/action responsible for the logout procedure or navigates a user to the place where they can log out themselves.
|
||||
* The method must call `SettingsSyncEvents.getInstance().fireLoginStateChanged()` in order to propagate the changed state.
|
||||
* If function is null, logout link in the UI is not visible
|
||||
* If the function is null, a logout link in the UI is not visible
|
||||
*/
|
||||
val logoutFunction: (suspend (Component?) -> Unit)?
|
||||
get() = null
|
||||
@@ -62,6 +70,6 @@ interface SettingsSyncAuthService {
|
||||
val message: @Nls String,
|
||||
val actionTitle: @Nls String,
|
||||
val actionDescription: @Nls String? = null,
|
||||
val action: suspend (Component?) -> Unit
|
||||
val action: suspend (Component?) -> Unit,
|
||||
)
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
@file:OptIn(IntellijInternalApi::class)
|
||||
|
||||
package com.intellij.settingsSync.core.communicator
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
@@ -16,6 +18,7 @@ import com.intellij.openapi.extensions.PluginId
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.openapi.updateSettings.impl.PluginDownloader
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.IntellijInternalApi
|
||||
import com.intellij.platform.ide.progress.ModalTaskOwner
|
||||
import com.intellij.platform.ide.progress.TaskCancellation
|
||||
import com.intellij.platform.ide.progress.withModalProgress
|
||||
@@ -141,7 +144,7 @@ object RemoteCommunicatorHolder : SettingsSyncEventListener {
|
||||
|
||||
fun getAvailableProviders(): List<SettingsSyncCommunicatorProvider> {
|
||||
val extensionList = arrayListOf<SettingsSyncCommunicatorProvider>()
|
||||
extensionList.addAll(SettingsSyncCommunicatorProvider.PROVIDER_EP.extensionList.filter { it.isAvailable() })
|
||||
extensionList.addAll(getAvailableSyncProviders())
|
||||
if (extensionList.find { it.providerCode == DEFAULT_PROVIDER_CODE } == null) {
|
||||
extensionList.add(DelegatingDefaultCommunicatorProvider)
|
||||
}
|
||||
@@ -242,7 +245,7 @@ object RemoteCommunicatorHolder : SettingsSyncEventListener {
|
||||
return null
|
||||
}
|
||||
|
||||
val defaultProvider = SettingsSyncCommunicatorProvider.PROVIDER_EP.extensionList.find { it.providerCode == DEFAULT_PROVIDER_CODE }
|
||||
val defaultProvider = getAvailableSyncProviders().find { it.providerCode == DEFAULT_PROVIDER_CODE }
|
||||
?: return null
|
||||
DelegatingDefaultCommunicatorProvider.delegate = defaultProvider
|
||||
return defaultProvider.authService.login(parentComponent)
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
@file:OptIn(IntellijInternalApi::class)
|
||||
|
||||
package com.intellij.settingsSync.core.communicator
|
||||
|
||||
import com.intellij.ide.plugins.PluginManagerCore
|
||||
import com.intellij.openapi.extensions.ExtensionPoint
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.extensions.RequiredElement
|
||||
import com.intellij.openapi.util.IntellijInternalApi
|
||||
import com.intellij.serviceContainer.BaseKeyedLazyInstance
|
||||
import com.intellij.util.xmlb.annotations.Attribute
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
|
||||
@ApiStatus.Internal
|
||||
open class SettingsSyncCommunicatorBean : BaseKeyedLazyInstance<SettingsSyncCommunicatorProvider>() {
|
||||
@Attribute("implementation")
|
||||
@JvmField
|
||||
@RequiredElement
|
||||
var implementation: String = ""
|
||||
|
||||
override fun getImplementationClassName(): String = implementation
|
||||
}
|
||||
|
||||
private val PROVIDER_EP: ExtensionPointName<SettingsSyncCommunicatorBean> =
|
||||
ExtensionPointName.create("com.intellij.settingsSync.communicatorProvider")
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@TestOnly
|
||||
@ApiStatus.Internal
|
||||
fun getSyncProviderPoint(): ExtensionPoint<SettingsSyncCommunicatorBean> {
|
||||
return PROVIDER_EP.point
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun getAvailableSyncProviders(): List<SettingsSyncCommunicatorProvider> {
|
||||
return PROVIDER_EP.extensionList
|
||||
.filter {
|
||||
val plugin = it.pluginDescriptor
|
||||
val vendorName = plugin.vendor ?: plugin.organization ?: ""
|
||||
|
||||
plugin.isBundled
|
||||
|| PluginManagerCore.isDevelopedByJetBrains(plugin)
|
||||
|| PluginManagerCore.isVendorItemTrusted(vendorName)
|
||||
}
|
||||
.map { bean -> bean.instance }
|
||||
.filter { it.isAvailable() }
|
||||
}
|
||||
@@ -1,9 +1,19 @@
|
||||
package com.intellij.settingsSync.core.communicator
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.util.IntellijInternalApi
|
||||
import com.intellij.settingsSync.core.SettingsSyncRemoteCommunicator
|
||||
import com.intellij.settingsSync.core.auth.SettingsSyncAuthService
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
/**
|
||||
* This is an internal extension that requires an explicit license agreement with JetBrains s.r.o. for plugins.
|
||||
* Only IDE-bundled plugins are allowed to implement it.
|
||||
*
|
||||
* Contact https://platform.jetbrains.com/ for details.
|
||||
* You may not use this extension until it is unlocked in the platform for your plugin.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@IntellijInternalApi
|
||||
interface SettingsSyncCommunicatorProvider {
|
||||
|
||||
/**
|
||||
@@ -27,7 +37,7 @@ interface SettingsSyncCommunicatorProvider {
|
||||
|
||||
/**
|
||||
* Used in the select provider dialog.
|
||||
* a Pair:
|
||||
* A pair contains:
|
||||
* * link text, for instance: Learn more
|
||||
* * actual link itself, for instance: https://www.jetbrains.com/help/idea/sharing-your-ide-settings.html
|
||||
*/
|
||||
@@ -40,14 +50,9 @@ interface SettingsSyncCommunicatorProvider {
|
||||
fun createCommunicator(userId: String): SettingsSyncRemoteCommunicator?
|
||||
|
||||
/**
|
||||
* Indicates whether provider is available. Allows to control provider availability inside the plugin
|
||||
* Indicates whether a provider is available. Allows controlling provider availability inside the plugin
|
||||
*/
|
||||
fun isAvailable(): Boolean = true
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val PROVIDER_EP = ExtensionPointName.create<SettingsSyncCommunicatorProvider>("com.intellij.settingsSync.communicatorProvider")
|
||||
}
|
||||
}
|
||||
|
||||
data class SettingsSyncUserData(
|
||||
@@ -55,5 +60,5 @@ data class SettingsSyncUserData(
|
||||
val providerCode: String,
|
||||
val name: String?,
|
||||
val email: String?,
|
||||
val printableName: String? = null
|
||||
val printableName: String? = null,
|
||||
)
|
||||
@@ -1,3 +1,5 @@
|
||||
@file:OptIn(IntellijInternalApi::class)
|
||||
|
||||
package com.intellij.settingsSync.core.config
|
||||
|
||||
|
||||
@@ -27,6 +29,7 @@ import com.intellij.openapi.ui.popup.ListSeparator
|
||||
import com.intellij.openapi.ui.popup.PopupStep
|
||||
import com.intellij.openapi.ui.popup.util.BaseListPopupStep
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.IntellijInternalApi
|
||||
import com.intellij.platform.ide.progress.ModalTaskOwner
|
||||
import com.intellij.platform.ide.progress.TaskCancellation
|
||||
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
|
||||
@@ -37,6 +40,7 @@ import com.intellij.settingsSync.core.auth.SettingsSyncAuthService.PendingUserAc
|
||||
import com.intellij.settingsSync.core.communicator.RemoteCommunicatorHolder
|
||||
import com.intellij.settingsSync.core.communicator.SettingsSyncCommunicatorProvider
|
||||
import com.intellij.settingsSync.core.communicator.SettingsSyncUserData
|
||||
import com.intellij.settingsSync.core.communicator.getAvailableSyncProviders
|
||||
import com.intellij.settingsSync.core.config.SettingsSyncEnabler.State
|
||||
import com.intellij.settingsSync.core.statistics.SettingsSyncEventsStatistics
|
||||
import com.intellij.ui.RelativeFont
|
||||
@@ -128,11 +132,15 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
||||
val authService = userProviderHolder?.let { RemoteCommunicatorHolder.getProvider(userProviderHolder.providerCode) } ?.authService
|
||||
syncPanelHolder.crossSyncSupported.set(authService?.crossSyncSupported() ?: true)
|
||||
val infoRow = row {
|
||||
@Suppress("DialogTitleCapitalization")
|
||||
text(message("settings.sync.info.message"))
|
||||
SettingsSyncCommunicatorProvider.PROVIDER_EP.extensionList.firstOrNull { it.isAvailable() && it.learnMoreLinkPair != null }?.also {
|
||||
val linkPair = it.learnMoreLinkPair!!
|
||||
browserLink(linkPair.first, linkPair.second)
|
||||
}
|
||||
getAvailableSyncProviders()
|
||||
.firstOrNull { it.learnMoreLinkPair != null }
|
||||
?.also {
|
||||
val linkPair = it.learnMoreLinkPair!!
|
||||
@Suppress("HardCodedStringLiteral")
|
||||
browserLink(linkPair.first, linkPair.second)
|
||||
}
|
||||
}
|
||||
|
||||
rowsRange {
|
||||
@@ -698,7 +706,7 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
||||
}
|
||||
}
|
||||
|
||||
// triggers fake action, which causes SettingEditor to update and check if configurable was modified
|
||||
// triggers a fake action, which causes SettingEditor to update and check if configurable was modified
|
||||
// must be called on EDT
|
||||
private fun triggerUpdateConfigurable() {
|
||||
val dumbAwareAction = DumbAwareAction.create(Consumer { _: AnActionEvent? ->
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
@file:OptIn(IntellijInternalApi::class)
|
||||
|
||||
package com.intellij.settingsSync.core
|
||||
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.util.IntellijInternalApi
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.settingsSync.core.auth.SettingsSyncAuthService
|
||||
import com.intellij.settingsSync.core.communicator.SettingsSyncCommunicatorProvider
|
||||
@@ -163,9 +166,10 @@ internal class MockRemoteCommunicator(override val userId: String) : AbstractSer
|
||||
internal class MockCommunicatorProvider (
|
||||
private val remoteCommunicator: SettingsSyncRemoteCommunicator,
|
||||
override val authService: SettingsSyncAuthService,
|
||||
private val code: String? = null
|
||||
): SettingsSyncCommunicatorProvider {
|
||||
override val providerCode: String
|
||||
get() = MOCK_CODE
|
||||
get() = code ?: MOCK_CODE
|
||||
|
||||
override fun createCommunicator(userId: String): SettingsSyncRemoteCommunicator? = remoteCommunicator
|
||||
}
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
@file:OptIn(IntellijInternalApi::class)
|
||||
|
||||
package com.intellij.settingsSync.core
|
||||
|
||||
import com.intellij.ide.plugins.PluginManagerCore.VENDOR_JETBRAINS
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.impl.ApplicationImpl
|
||||
import com.intellij.openapi.components.ComponentManager
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.settingsSync.core.communicator.RemoteCommunicatorHolder
|
||||
import com.intellij.settingsSync.core.communicator.SettingsSyncCommunicatorProvider
|
||||
import com.intellij.settingsSync.core.communicator.SettingsSyncUserData
|
||||
import com.intellij.openapi.extensions.DefaultPluginDescriptor
|
||||
import com.intellij.openapi.extensions.PluginDescriptor
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import com.intellij.openapi.util.IntellijInternalApi
|
||||
import com.intellij.settingsSync.core.communicator.*
|
||||
import com.intellij.testFramework.common.DEFAULT_TEST_TIMEOUT
|
||||
import com.intellij.testFramework.common.timeoutRunBlocking
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
@@ -29,13 +35,11 @@ import kotlin.time.Duration
|
||||
|
||||
internal val TIMEOUT_UNIT = TimeUnit.SECONDS
|
||||
|
||||
private val LOG = logger<SettingsSyncTestBase>()
|
||||
|
||||
@TestApplication
|
||||
internal abstract class SettingsSyncTestBase {
|
||||
|
||||
companion object {
|
||||
val LOG = logger<SettingsSyncTestBase>()
|
||||
}
|
||||
|
||||
protected lateinit var application: ApplicationImpl
|
||||
protected lateinit var configDir: Path
|
||||
protected lateinit var remoteCommunicator: MockRemoteCommunicator
|
||||
@@ -61,11 +65,11 @@ internal abstract class SettingsSyncTestBase {
|
||||
else {
|
||||
MockRemoteCommunicator("mockUser").apply {this.isConnected = true }
|
||||
}
|
||||
val providerEP = SettingsSyncCommunicatorProvider.PROVIDER_EP.point
|
||||
val providerEP = getSyncProviderPoint()
|
||||
if (providerEP.extensions.size > 0) {
|
||||
LOG.warn("SettingsSyncCommunicatorProvider.PROVIDER_EP is not empty: ${providerEP.extensions.toList()}")
|
||||
providerEP.extensions.forEach {
|
||||
LOG.warn("Unregistering extension: ${it.javaClass.name}")
|
||||
for (it in providerEP.extensions) {
|
||||
LOG.warn("Unregistering extension: ${it.instance.javaClass.name}")
|
||||
providerEP.unregisterExtension(it)
|
||||
}
|
||||
}
|
||||
@@ -76,7 +80,21 @@ internal abstract class SettingsSyncTestBase {
|
||||
remoteCommunicator,
|
||||
authService
|
||||
)
|
||||
providerEP.registerExtension(mockCommunicatorProvider, disposable)
|
||||
providerEP.registerExtension(object : SettingsSyncCommunicatorBean() {
|
||||
init {
|
||||
this.pluginDescriptor = DefaultPluginDescriptor(
|
||||
PluginId.getId("com.intellij.settingsSync"),
|
||||
SettingsSyncTestBase::class.java.getClassLoader(),
|
||||
VENDOR_JETBRAINS
|
||||
)
|
||||
}
|
||||
|
||||
override fun createInstance(
|
||||
componentManager: ComponentManager,
|
||||
pluginDescriptor: PluginDescriptor,
|
||||
): SettingsSyncCommunicatorProvider = mockCommunicatorProvider
|
||||
}, disposable)
|
||||
|
||||
SettingsSyncLocalSettings.getInstance().providerCode = mockCommunicatorProvider.providerCode
|
||||
SettingsSyncLocalSettings.getInstance().userId = DUMMY_USER_ID
|
||||
|
||||
@@ -149,7 +167,6 @@ internal abstract class SettingsSyncTestBase {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal fun CountDownLatch.wait(): Boolean {
|
||||
return this.await(getDefaultTimeoutInSeconds(), TIMEOUT_UNIT)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
@file:OptIn(IntellijInternalApi::class)
|
||||
|
||||
package com.intellij.settingsSync.core
|
||||
|
||||
import com.intellij.ide.plugins.PluginManagerCore.VENDOR_JETBRAINS
|
||||
import com.intellij.openapi.components.ComponentManager
|
||||
import com.intellij.openapi.extensions.DefaultPluginDescriptor
|
||||
import com.intellij.openapi.extensions.PluginDescriptor
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import com.intellij.openapi.util.IntellijInternalApi
|
||||
import com.intellij.settingsSync.core.communicator.SettingsSyncCommunicatorBean
|
||||
import com.intellij.settingsSync.core.communicator.SettingsSyncCommunicatorProvider
|
||||
import com.intellij.settingsSync.core.communicator.getAvailableSyncProviders
|
||||
import com.intellij.settingsSync.core.communicator.getSyncProviderPoint
|
||||
import com.intellij.testFramework.UsefulTestCase.assertSize
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
internal class SettingSyncVendorsTest : SettingsSyncTestBase() {
|
||||
@BeforeEach
|
||||
fun setupProviders() {
|
||||
val providerPoint = getSyncProviderPoint()
|
||||
|
||||
providerPoint.registerExtension(object : SettingsSyncCommunicatorBean() {
|
||||
init {
|
||||
this.pluginDescriptor = DefaultPluginDescriptor(
|
||||
PluginId.getId("com.intellij.allowed.sync.provider"),
|
||||
SettingsSyncTestBase::class.java.getClassLoader(),
|
||||
VENDOR_JETBRAINS
|
||||
)
|
||||
}
|
||||
|
||||
override fun createInstance(
|
||||
componentManager: ComponentManager,
|
||||
pluginDescriptor: PluginDescriptor,
|
||||
): SettingsSyncCommunicatorProvider = MockCommunicatorProvider(
|
||||
remoteCommunicator,
|
||||
authService,
|
||||
"ALLOWED_PROVIDER"
|
||||
)
|
||||
}, disposable)
|
||||
|
||||
providerPoint.registerExtension(object : SettingsSyncCommunicatorBean() {
|
||||
init {
|
||||
this.pluginDescriptor = DefaultPluginDescriptor(
|
||||
PluginId.getId("com.intellij.3rd.party.provider"),
|
||||
SettingsSyncTestBase::class.java.getClassLoader(),
|
||||
"YourCompany"
|
||||
)
|
||||
}
|
||||
|
||||
override fun createInstance(
|
||||
componentManager: ComponentManager,
|
||||
pluginDescriptor: PluginDescriptor,
|
||||
): SettingsSyncCommunicatorProvider = MockCommunicatorProvider(
|
||||
remoteCommunicator,
|
||||
authService,
|
||||
"UNAUTHORIZED_PROVIDER"
|
||||
)
|
||||
}, disposable)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUnauthorizedProviderIsExcluded() {
|
||||
val extensions = getSyncProviderPoint().extensionList
|
||||
assertSize(3, extensions) // precondition, everything registered
|
||||
|
||||
val availableSyncProviders = getAvailableSyncProviders()
|
||||
assertSize(2, availableSyncProviders)
|
||||
|
||||
val codes = availableSyncProviders.map { it.providerCode }
|
||||
|
||||
assertTrue(codes.contains("ALLOWED_PROVIDER"), "ALLOWED_PROVIDER must be present in the list")
|
||||
assertFalse(codes.contains("UNAUTHORIZED_PROVIDER"), "UNAUTHORIZED_PROVIDER must be absent from the list")
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.internal.statistic;
|
||||
|
||||
import com.intellij.internal.statistic.utils.PluginInfoDetectorKt;
|
||||
import com.intellij.openapi.application.ex.ApplicationInfoEx;
|
||||
import com.intellij.openapi.application.impl.ApplicationInfoImpl;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -23,6 +22,8 @@ import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
import java.util.prefs.Preferences;
|
||||
|
||||
import static com.intellij.ide.plugins.PluginManagerCoreKt.isPlatformOrJetBrainsBundled;
|
||||
|
||||
public final class DeviceIdManager {
|
||||
private static final Logger LOG = Logger.getInstance(DeviceIdManager.class);
|
||||
|
||||
@@ -60,7 +61,7 @@ public final class DeviceIdManager {
|
||||
if (token == null) {
|
||||
throw new InvalidDeviceIdTokenException("Cannot access base device id from unknown class");
|
||||
}
|
||||
else if (!PluginInfoDetectorKt.isPlatformOrJetBrainsBundled(token.getClass())) {
|
||||
else if (!isPlatformOrJetBrainsBundled(token.getClass())) {
|
||||
throw new InvalidDeviceIdTokenException("Cannot access base device id from " + token.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,22 +27,6 @@ fun getPluginInfo(aClass: Class<*>): PluginInfo {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun isPlatformOrJetBrainsBundled(aClass: Class<*>): Boolean {
|
||||
val classLoader = aClass.classLoader
|
||||
when {
|
||||
classLoader is PluginAwareClassLoader -> {
|
||||
val plugin = classLoader.pluginDescriptor
|
||||
return plugin.isBundled && PluginManagerCore.isDevelopedByJetBrains(plugin)
|
||||
}
|
||||
PluginManagerCore.isRunningFromSources() -> {
|
||||
return true
|
||||
}
|
||||
else -> {
|
||||
return PluginUtils.getPluginDescriptorIfIdeaClassLoaderIsUsed(aClass) == null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun hasStandardExceptionPrefix(className: String): Boolean =
|
||||
className.startsWith("java.") || className.startsWith("javax.") ||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package com.intellij.settingsSync.jba.auth
|
||||
|
||||
import com.intellij.CommonBundle
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.ide.plugins.PluginManagerCore
|
||||
import com.intellij.idea.AppMode
|
||||
import com.intellij.openapi.actionSystem.*
|
||||
import com.intellij.openapi.actionSystem.ex.ActionUtil
|
||||
import com.intellij.openapi.actionSystem.ex.ActionUtil.performAction
|
||||
import com.intellij.openapi.actionSystem.ex.ActionUtil.performActionDumbAwareWithCallbacks
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
import com.intellij.openapi.application.asContextElement
|
||||
@@ -48,13 +46,10 @@ import javax.swing.event.HyperlinkEvent
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
|
||||
private val LOG = logger<JBAAuthService>()
|
||||
private const val JBA_USER_ID = "jba"
|
||||
|
||||
internal class JBAAuthService(private val cs: CoroutineScope) : SettingsSyncAuthService {
|
||||
|
||||
companion object {
|
||||
private val LOG = logger<JBAAuthService>()
|
||||
private const val JBA_USER_ID = "jba"
|
||||
}
|
||||
|
||||
@Volatile
|
||||
private var invalidatedIdToken: String? = null
|
||||
|
||||
|
||||
Reference in New Issue
Block a user