diff --git a/src/main/java/ee/carlrobert/codegpt/actions/GenerateGitCommitMessageAction.java b/src/main/java/ee/carlrobert/codegpt/actions/GenerateGitCommitMessageAction.java index eadbb06d..0e5b07bf 100644 --- a/src/main/java/ee/carlrobert/codegpt/actions/GenerateGitCommitMessageAction.java +++ b/src/main/java/ee/carlrobert/codegpt/actions/GenerateGitCommitMessageAction.java @@ -2,11 +2,6 @@ package ee.carlrobert.codegpt.actions; import static com.intellij.openapi.ui.Messages.OK; import static com.intellij.util.ObjectUtils.tryCast; -import static ee.carlrobert.codegpt.settings.service.ServiceType.ANTHROPIC; -import static ee.carlrobert.codegpt.settings.service.ServiceType.AZURE; -import static ee.carlrobert.codegpt.settings.service.ServiceType.CUSTOM_OPENAI; -import static ee.carlrobert.codegpt.settings.service.ServiceType.LLAMA_CPP; -import static ee.carlrobert.codegpt.settings.service.ServiceType.OPENAI; import static ee.carlrobert.codegpt.settings.service.ServiceType.YOU; import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; @@ -34,10 +29,7 @@ import ee.carlrobert.codegpt.CodeGPTBundle; import ee.carlrobert.codegpt.EncodingManager; import ee.carlrobert.codegpt.Icons; import ee.carlrobert.codegpt.completions.CompletionRequestService; -import ee.carlrobert.codegpt.credentials.AzureCredentialsManager; -import ee.carlrobert.codegpt.credentials.OpenAICredentialManager; import ee.carlrobert.codegpt.settings.GeneralSettings; -import ee.carlrobert.codegpt.settings.service.ServiceType; import ee.carlrobert.codegpt.ui.OverlayUtil; import ee.carlrobert.llm.client.openai.completion.ErrorDetails; import ee.carlrobert.llm.completion.CompletionEventListener; @@ -79,19 +71,14 @@ public class GenerateGitCommitMessageAction extends AnAction { var includedUnversionedChangesFilePaths = getIncludedUnversionedFilePaths(event); var filesSelected = !includedChangesFilePaths.isEmpty() || !includedUnversionedChangesFilePaths.isEmpty(); - var callAllowed = isCallAllowed(selectedService); + var callAllowed = CompletionRequestService.isRequestAllowed( + GeneralSettings.getCurrentState().getSelectedService()); event.getPresentation().setEnabled(callAllowed && filesSelected); event.getPresentation().setText(CodeGPTBundle.get(callAllowed ? "action.generateCommitMessage.title" : "action.generateCommitMessage.missingCredentials")); } - private boolean isCallAllowed(ServiceType serviceType) { - return (serviceType == OPENAI && OpenAICredentialManager.getInstance().isCredentialSet()) - || (serviceType == AZURE && AzureCredentialsManager.getInstance().isCredentialSet()) - || List.of(LLAMA_CPP, ANTHROPIC, CUSTOM_OPENAI).contains(serviceType); - } - @Override public void actionPerformed(@NotNull AnActionEvent event) { var project = event.getProject(); diff --git a/src/main/java/ee/carlrobert/codegpt/completions/CompletionClientProvider.java b/src/main/java/ee/carlrobert/codegpt/completions/CompletionClientProvider.java index ef1ad528..9f7cdf93 100644 --- a/src/main/java/ee/carlrobert/codegpt/completions/CompletionClientProvider.java +++ b/src/main/java/ee/carlrobert/codegpt/completions/CompletionClientProvider.java @@ -2,10 +2,8 @@ package ee.carlrobert.codegpt.completions; import ee.carlrobert.codegpt.CodeGPTPlugin; import ee.carlrobert.codegpt.completions.you.YouUserManager; -import ee.carlrobert.codegpt.credentials.AnthropicCredentialsManager; -import ee.carlrobert.codegpt.credentials.AzureCredentialsManager; -import ee.carlrobert.codegpt.credentials.LlamaCredentialManager; -import ee.carlrobert.codegpt.credentials.OpenAICredentialManager; +import ee.carlrobert.codegpt.credentials.CredentialsStore; +import ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey; import ee.carlrobert.codegpt.settings.advanced.AdvancedSettings; import ee.carlrobert.codegpt.settings.service.anthropic.AnthropicSettings; import ee.carlrobert.codegpt.settings.service.azure.AzureSettings; @@ -23,18 +21,23 @@ import java.net.Proxy; import java.util.concurrent.TimeUnit; import okhttp3.Credentials; import okhttp3.OkHttpClient; +import org.jetbrains.annotations.Nullable; public class CompletionClientProvider { + private static @Nullable String getCredential(CredentialKey key) { + return CredentialsStore.INSTANCE.getCredential(key); + } + public static OpenAIClient getOpenAIClient() { - return new OpenAIClient.Builder(OpenAICredentialManager.getInstance().getCredential()) + return new OpenAIClient.Builder(getCredential(CredentialKey.OPENAI_API_KEY)) .setOrganization(OpenAISettings.getCurrentState().getOrganization()) .build(getDefaultClientBuilder()); } public static ClaudeClient getClaudeClient() { return new ClaudeClient( - AnthropicCredentialsManager.getInstance().getCredential(), + getCredential(CredentialKey.ANTHROPIC_API_KEY), AnthropicSettings.getCurrentState().getApiVersion(), getDefaultClientBuilder()); } @@ -45,8 +48,12 @@ public class CompletionClientProvider { settings.getResourceName(), settings.getDeploymentId(), settings.getApiVersion()); - return new AzureClient.Builder(AzureCredentialsManager.getInstance().getCredential(), params) - .setActiveDirectoryAuthentication(settings.isUseAzureActiveDirectoryAuthentication()) + var useAzureActiveDirectoryAuthentication = settings.isUseAzureActiveDirectoryAuthentication(); + var credential = useAzureActiveDirectoryAuthentication + ? getCredential(CredentialKey.AZURE_ACTIVE_DIRECTORY_TOKEN) + : getCredential(CredentialKey.AZURE_OPENAI_API_KEY); + return new AzureClient.Builder(credential, params) + .setActiveDirectoryAuthentication(useAzureActiveDirectoryAuthentication) .build(getDefaultClientBuilder()); } @@ -77,7 +84,7 @@ public class CompletionClientProvider { .setPort(llamaSettings.getServerPort()); if (!llamaSettings.isRunLocalServer()) { builder.setHost(llamaSettings.getBaseHost()); - String apiKey = LlamaCredentialManager.getInstance().getCredential(); + String apiKey = getCredential(CredentialKey.LLAMA_API_KEY); if (apiKey != null && !apiKey.isBlank()) { builder.setApiKey(apiKey); } diff --git a/src/main/java/ee/carlrobert/codegpt/completions/CompletionRequestProvider.java b/src/main/java/ee/carlrobert/codegpt/completions/CompletionRequestProvider.java index c57d5ea1..d43109fb 100644 --- a/src/main/java/ee/carlrobert/codegpt/completions/CompletionRequestProvider.java +++ b/src/main/java/ee/carlrobert/codegpt/completions/CompletionRequestProvider.java @@ -1,5 +1,6 @@ package ee.carlrobert.codegpt.completions; +import static ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.CUSTOM_SERVICE_API_KEY; import static ee.carlrobert.codegpt.util.file.FileUtil.getResourceContent; import static java.lang.String.format; import static java.util.stream.Collectors.joining; @@ -16,7 +17,7 @@ import ee.carlrobert.codegpt.completions.llama.PromptTemplate; import ee.carlrobert.codegpt.conversations.Conversation; import ee.carlrobert.codegpt.conversations.ConversationsState; import ee.carlrobert.codegpt.conversations.message.Message; -import ee.carlrobert.codegpt.credentials.CustomServiceCredentialManager; +import ee.carlrobert.codegpt.credentials.CredentialsStore; import ee.carlrobert.codegpt.settings.GeneralSettings; import ee.carlrobert.codegpt.settings.IncludedFilesSettings; import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings; @@ -202,9 +203,9 @@ public class CompletionRequestProvider { var requestBuilder = new Request.Builder().url(customConfiguration.getUrl().trim()); for (var entry : customConfiguration.getHeaders().entrySet()) { String value = entry.getValue(); - if (value.contains("$CUSTOM_SERVICE_API_KEY")) { - value = value.replace("$CUSTOM_SERVICE_API_KEY", - CustomServiceCredentialManager.getInstance().getCredential()); + var credential = CredentialsStore.INSTANCE.getCredential(CUSTOM_SERVICE_API_KEY); + if (value.contains("$CUSTOM_SERVICE_API_KEY") && credential != null) { + value = value.replace("$CUSTOM_SERVICE_API_KEY", credential); } requestBuilder.addHeader(entry.getKey(), value); } diff --git a/src/main/java/ee/carlrobert/codegpt/completions/CompletionRequestService.java b/src/main/java/ee/carlrobert/codegpt/completions/CompletionRequestService.java index 04c015c2..229c9ee8 100644 --- a/src/main/java/ee/carlrobert/codegpt/completions/CompletionRequestService.java +++ b/src/main/java/ee/carlrobert/codegpt/completions/CompletionRequestService.java @@ -1,5 +1,6 @@ package ee.carlrobert.codegpt.completions; +import static ee.carlrobert.codegpt.settings.service.ServiceType.ANTHROPIC; import static ee.carlrobert.codegpt.settings.service.ServiceType.AZURE; import static ee.carlrobert.codegpt.settings.service.ServiceType.CUSTOM_OPENAI; import static ee.carlrobert.codegpt.settings.service.ServiceType.LLAMA_CPP; @@ -13,11 +14,13 @@ import ee.carlrobert.codegpt.codecompletions.CodeCompletionRequestProvider; import ee.carlrobert.codegpt.codecompletions.InfillRequestDetails; import ee.carlrobert.codegpt.completions.llama.LlamaModel; import ee.carlrobert.codegpt.completions.llama.PromptTemplate; -import ee.carlrobert.codegpt.credentials.AzureCredentialsManager; -import ee.carlrobert.codegpt.credentials.OpenAICredentialManager; +import ee.carlrobert.codegpt.credentials.CredentialsStore; +import ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey; import ee.carlrobert.codegpt.settings.GeneralSettings; import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings; +import ee.carlrobert.codegpt.settings.service.ServiceType; import ee.carlrobert.codegpt.settings.service.anthropic.AnthropicSettings; +import ee.carlrobert.codegpt.settings.service.azure.AzureSettings; import ee.carlrobert.codegpt.settings.service.custom.CustomServiceSettings; import ee.carlrobert.codegpt.settings.service.llama.LlamaSettings; import ee.carlrobert.codegpt.settings.service.openai.OpenAISettings; @@ -197,6 +200,26 @@ public final class CompletionRequestService { return tryExtractContent(response); } + public boolean isRequestAllowed() { + return isRequestAllowed(GeneralSettings.getCurrentState().getSelectedService()); + } + + public static boolean isRequestAllowed(ServiceType serviceType) { + if (serviceType == OPENAI + && CredentialsStore.INSTANCE.isCredentialSet(CredentialKey.OPENAI_API_KEY)) { + return true; + } + + var azureCredentialKey = AzureSettings.getCurrentState().isUseAzureApiKeyAuthentication() + ? CredentialKey.AZURE_OPENAI_API_KEY + : CredentialKey.AZURE_ACTIVE_DIRECTORY_TOKEN; + if (serviceType == AZURE && CredentialsStore.INSTANCE.isCredentialSet(azureCredentialKey)) { + return true; + } + + return List.of(LLAMA_CPP, ANTHROPIC, CUSTOM_OPENAI).contains(serviceType); + } + private Optional tryExtractContent(OpenAIChatCompletionResponse response) { return response .getChoices() @@ -204,15 +227,4 @@ public final class CompletionRequestService { .findFirst() .map(item -> item.getMessage().getContent()); } - - public boolean isRequestAllowed() { - var selectedService = GeneralSettings.getCurrentState().getSelectedService(); - if (selectedService == AZURE) { - return AzureCredentialsManager.getInstance().isCredentialSet(); - } - if (selectedService == OPENAI) { - return OpenAICredentialManager.getInstance().isCredentialSet(); - } - return true; - } } diff --git a/src/main/java/ee/carlrobert/codegpt/completions/MethodNameLookupListener.java b/src/main/java/ee/carlrobert/codegpt/completions/MethodNameLookupListener.java index a5d4ffd7..1b44013c 100644 --- a/src/main/java/ee/carlrobert/codegpt/completions/MethodNameLookupListener.java +++ b/src/main/java/ee/carlrobert/codegpt/completions/MethodNameLookupListener.java @@ -10,7 +10,8 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiUtilCore; import ee.carlrobert.codegpt.Icons; -import ee.carlrobert.codegpt.credentials.OpenAICredentialManager; +import ee.carlrobert.codegpt.credentials.CredentialsStore; +import ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey; import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings; import java.util.Optional; import org.jetbrains.annotations.Nullable; @@ -21,15 +22,13 @@ public class MethodNameLookupListener implements LookupManagerListener { public void activeLookupChanged(@Nullable Lookup oldLookup, @Nullable Lookup newLookup) { var application = ApplicationManager.getApplication(); var configuration = ConfigurationSettings.getCurrentState(); - var credentialsManager = OpenAICredentialManager.getInstance(); if (!configuration.isMethodNameGenerationEnabled() - || !credentialsManager.isCredentialSet() - || !(newLookup instanceof LookupImpl)) { + || !CredentialsStore.INSTANCE.isCredentialSet(CredentialKey.OPENAI_API_KEY) + || !(newLookup instanceof LookupImpl lookup)) { return; } - var lookup = (LookupImpl) newLookup; Optional.ofNullable(lookup.getPsiElement()) .map(PsiElement::getContext) .ifPresent(context -> diff --git a/src/main/java/ee/carlrobert/codegpt/credentials/AbstractCredentialsManager.java b/src/main/java/ee/carlrobert/codegpt/credentials/AbstractCredentialsManager.java deleted file mode 100644 index 2d067ca8..00000000 --- a/src/main/java/ee/carlrobert/codegpt/credentials/AbstractCredentialsManager.java +++ /dev/null @@ -1,55 +0,0 @@ -package ee.carlrobert.codegpt.credentials; - -import com.intellij.credentialStore.CredentialAttributes; -import com.intellij.credentialStore.CredentialAttributesKt; -import com.intellij.ide.passwordSafe.PasswordSafe; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.jetbrains.annotations.Nullable; - -abstract class AbstractCredentialsManager { - - private final Map credentialMapping; - private final Map credentialCache = new ConcurrentHashMap<>(); - - protected AbstractCredentialsManager(String... keys) { - credentialMapping = Stream.of(keys).collect(Collectors.toConcurrentMap( - key -> key, - key -> new CredentialAttributes(CredentialAttributesKt.generateServiceName("CodeGPT", key)) - )); - } - - public abstract boolean isCredentialSet(); - - protected boolean isCredentialSet(String key) { - var credential = getCredential(key); - return credential != null && !credential.isEmpty(); - } - - public abstract String getCredential(); - - protected @Nullable String getCredential(String key) { - String cachedCredential = credentialCache.get(key); - if (cachedCredential != null) { - return cachedCredential; - } - - String credential = PasswordSafe.getInstance().getPassword(credentialMapping.get(key)); - if (credential != null) { - credentialCache.put(key, credential); - } - return credential; - } - - protected void setCredential(String key, String credential) { - if (credential == null) { - credentialCache.remove(key); - } else { - credentialCache.put(key, credential); - } - - PasswordSafe.getInstance().setPassword(credentialMapping.get(key), credential); - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/credentials/AnthropicCredentialsManager.java b/src/main/java/ee/carlrobert/codegpt/credentials/AnthropicCredentialsManager.java deleted file mode 100644 index 58fc4fa5..00000000 --- a/src/main/java/ee/carlrobert/codegpt/credentials/AnthropicCredentialsManager.java +++ /dev/null @@ -1,16 +0,0 @@ -package ee.carlrobert.codegpt.credentials; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.Service; - -@Service -public final class AnthropicCredentialsManager extends SingleCredentialManager { - - private AnthropicCredentialsManager() { - super("ANTHROPIC_API_KEY"); - } - - public static AnthropicCredentialsManager getInstance() { - return ApplicationManager.getApplication().getService(AnthropicCredentialsManager.class); - } -} \ No newline at end of file diff --git a/src/main/java/ee/carlrobert/codegpt/credentials/AzureCredentialsManager.java b/src/main/java/ee/carlrobert/codegpt/credentials/AzureCredentialsManager.java deleted file mode 100644 index c8e9842a..00000000 --- a/src/main/java/ee/carlrobert/codegpt/credentials/AzureCredentialsManager.java +++ /dev/null @@ -1,52 +0,0 @@ -package ee.carlrobert.codegpt.credentials; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.Service; -import ee.carlrobert.codegpt.settings.service.azure.AzureSettings; - -@Service -public final class AzureCredentialsManager extends AbstractCredentialsManager { - - public static final String API_KEY = "AZURE_OPENAI_API_KEY"; - public static final String ACTIVE_DIRECTORY_TOKEN = "AZURE_ACTIVE_DIRECTORY_TOKEN"; - - private AzureCredentialsManager() { - super(API_KEY, ACTIVE_DIRECTORY_TOKEN); - } - - public static AzureCredentialsManager getInstance() { - return ApplicationManager.getApplication().getService(AzureCredentialsManager.class); - } - - @Override - public boolean isCredentialSet() { - if (AzureSettings.getCurrentState().isUseAzureApiKeyAuthentication()) { - return isCredentialSet(API_KEY); - } - return isCredentialSet(ACTIVE_DIRECTORY_TOKEN); - } - - @Override - public String getCredential() { - if (AzureSettings.getCurrentState().isUseAzureActiveDirectoryAuthentication()) { - return getActiveDirectoryToken(); - } - return getApiKey(); - } - - public void setApiKey(String apiKey) { - setCredential(API_KEY, apiKey); - } - - public String getApiKey() { - return getCredential(API_KEY); - } - - public void setActiveDirectoryToken(String activeDirectoryToken) { - setCredential(ACTIVE_DIRECTORY_TOKEN, activeDirectoryToken); - } - - public String getActiveDirectoryToken() { - return getCredential(ACTIVE_DIRECTORY_TOKEN); - } -} \ No newline at end of file diff --git a/src/main/java/ee/carlrobert/codegpt/credentials/CustomServiceCredentialManager.java b/src/main/java/ee/carlrobert/codegpt/credentials/CustomServiceCredentialManager.java deleted file mode 100644 index 9b0f9dab..00000000 --- a/src/main/java/ee/carlrobert/codegpt/credentials/CustomServiceCredentialManager.java +++ /dev/null @@ -1,16 +0,0 @@ -package ee.carlrobert.codegpt.credentials; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.Service; - -@Service -public final class CustomServiceCredentialManager extends SingleCredentialManager { - - private CustomServiceCredentialManager() { - super("CUSTOM_SERVICE_API_KEY"); - } - - public static CustomServiceCredentialManager getInstance() { - return ApplicationManager.getApplication().getService(CustomServiceCredentialManager.class); - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/credentials/LlamaCredentialManager.java b/src/main/java/ee/carlrobert/codegpt/credentials/LlamaCredentialManager.java deleted file mode 100644 index ae47dbdc..00000000 --- a/src/main/java/ee/carlrobert/codegpt/credentials/LlamaCredentialManager.java +++ /dev/null @@ -1,16 +0,0 @@ -package ee.carlrobert.codegpt.credentials; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.Service; - -@Service -public final class LlamaCredentialManager extends SingleCredentialManager { - - private LlamaCredentialManager() { - super("LLAMA_API_KEY"); - } - - public static LlamaCredentialManager getInstance() { - return ApplicationManager.getApplication().getService(LlamaCredentialManager.class); - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/credentials/OpenAICredentialManager.java b/src/main/java/ee/carlrobert/codegpt/credentials/OpenAICredentialManager.java deleted file mode 100644 index bf23b4b7..00000000 --- a/src/main/java/ee/carlrobert/codegpt/credentials/OpenAICredentialManager.java +++ /dev/null @@ -1,16 +0,0 @@ -package ee.carlrobert.codegpt.credentials; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.Service; - -@Service -public final class OpenAICredentialManager extends SingleCredentialManager { - - private OpenAICredentialManager() { - super("OPENAI_API_KEY"); - } - - public static OpenAICredentialManager getInstance() { - return ApplicationManager.getApplication().getService(OpenAICredentialManager.class); - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/credentials/SingleCredentialManager.java b/src/main/java/ee/carlrobert/codegpt/credentials/SingleCredentialManager.java deleted file mode 100644 index 1596bfb5..00000000 --- a/src/main/java/ee/carlrobert/codegpt/credentials/SingleCredentialManager.java +++ /dev/null @@ -1,25 +0,0 @@ -package ee.carlrobert.codegpt.credentials; - -abstract class SingleCredentialManager extends AbstractCredentialsManager { - - private final String key; - - public SingleCredentialManager(String key) { - super(key); - this.key = key; - } - - @Override - public boolean isCredentialSet() { - return isCredentialSet(key); - } - - @Override - public String getCredential() { - return getCredential(key); - } - - public void setCredential(String credential) { - setCredential(key, credential); - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/credentials/YouCredentialManager.java b/src/main/java/ee/carlrobert/codegpt/credentials/YouCredentialManager.java deleted file mode 100644 index c1f013f0..00000000 --- a/src/main/java/ee/carlrobert/codegpt/credentials/YouCredentialManager.java +++ /dev/null @@ -1,16 +0,0 @@ -package ee.carlrobert.codegpt.credentials; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.Service; - -@Service -public final class YouCredentialManager extends SingleCredentialManager { - - private YouCredentialManager() { - super("YOU_ACCOUNT_PASSWORD"); - } - - public static YouCredentialManager getInstance() { - return ApplicationManager.getApplication().getService(YouCredentialManager.class); - } -} diff --git a/src/main/java/ee/carlrobert/codegpt/settings/GeneralSettingsConfigurable.java b/src/main/java/ee/carlrobert/codegpt/settings/GeneralSettingsConfigurable.java index 9d071c86..11063a53 100644 --- a/src/main/java/ee/carlrobert/codegpt/settings/GeneralSettingsConfigurable.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/GeneralSettingsConfigurable.java @@ -1,15 +1,18 @@ package ee.carlrobert.codegpt.settings; +import static ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.ANTHROPIC_API_KEY; +import static ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.AZURE_ACTIVE_DIRECTORY_TOKEN; +import static ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.AZURE_OPENAI_API_KEY; +import static ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.CUSTOM_SERVICE_API_KEY; +import static ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.LLAMA_API_KEY; +import static ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.OPENAI_API_KEY; + import com.intellij.openapi.Disposable; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.util.Disposer; import ee.carlrobert.codegpt.CodeGPTBundle; import ee.carlrobert.codegpt.conversations.ConversationsState; -import ee.carlrobert.codegpt.credentials.AnthropicCredentialsManager; -import ee.carlrobert.codegpt.credentials.AzureCredentialsManager; -import ee.carlrobert.codegpt.credentials.CustomServiceCredentialManager; -import ee.carlrobert.codegpt.credentials.LlamaCredentialManager; -import ee.carlrobert.codegpt.credentials.OpenAICredentialManager; +import ee.carlrobert.codegpt.credentials.CredentialsStore; import ee.carlrobert.codegpt.settings.service.anthropic.AnthropicSettings; import ee.carlrobert.codegpt.settings.service.anthropic.AnthropicSettingsForm; import ee.carlrobert.codegpt.settings.service.azure.AzureSettings; @@ -100,18 +103,20 @@ public class GeneralSettingsConfigurable implements Configurable { } private void applyOpenAISettings(OpenAISettingsForm form) { - OpenAICredentialManager.getInstance().setCredential(form.getApiKey()); + CredentialsStore.INSTANCE.setCredential(OPENAI_API_KEY, form.getApiKey()); OpenAISettings.getInstance().loadState(form.getCurrentState()); } private void applyCustomOpenAISettings(CustomServiceForm form) { - CustomServiceCredentialManager.getInstance().setCredential(form.getApiKey()); + CredentialsStore.INSTANCE.setCredential(CUSTOM_SERVICE_API_KEY, form.getApiKey()); CustomServiceSettings.getInstance().loadState(form.getCurrentState()); } private void applyLlamaSettings(LlamaSettingsForm form) { - LlamaCredentialManager.getInstance() - .setCredential(form.getLlamaServerPreferencesForm().getApiKey()); + CredentialsStore.INSTANCE.setCredential( + LLAMA_API_KEY, + form.getLlamaServerPreferencesForm().getApiKey()); + LlamaSettings.getInstance().loadState(form.getCurrentState()); } @@ -120,15 +125,16 @@ public class GeneralSettingsConfigurable implements Configurable { } private void applyAnthropicSettings(AnthropicSettingsForm form) { + CredentialsStore.INSTANCE.setCredential(ANTHROPIC_API_KEY, form.getApiKey()); AnthropicSettings.getInstance().loadState(form.getCurrentState()); - AnthropicCredentialsManager.getInstance().setCredential(form.getApiKey()); } private void applyAzureSettings(AzureSettingsForm form) { AzureSettings.getInstance().loadState(form.getCurrentState()); - var azureCredentials = AzureCredentialsManager.getInstance(); - azureCredentials.setApiKey(form.getApiKey()); - azureCredentials.setActiveDirectoryToken(form.getActiveDirectoryToken()); + CredentialsStore.INSTANCE.setCredential(AZURE_OPENAI_API_KEY, form.getApiKey()); + CredentialsStore.INSTANCE.setCredential( + AZURE_ACTIVE_DIRECTORY_TOKEN, + form.getActiveDirectoryToken()); } @Override diff --git a/src/main/java/ee/carlrobert/codegpt/settings/service/anthropic/AnthropicSettings.java b/src/main/java/ee/carlrobert/codegpt/settings/service/anthropic/AnthropicSettings.java index 9afab550..4ea11a0c 100644 --- a/src/main/java/ee/carlrobert/codegpt/settings/service/anthropic/AnthropicSettings.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/service/anthropic/AnthropicSettings.java @@ -4,7 +4,8 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.PersistentStateComponent; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; -import ee.carlrobert.codegpt.credentials.AnthropicCredentialsManager; +import ee.carlrobert.codegpt.credentials.CredentialsStore; +import ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; @@ -36,6 +37,6 @@ public class AnthropicSettings implements PersistentStateComponent( new EnumComboBoxModel<>(OpenAIChatCompletionModel.class)); @@ -77,7 +78,7 @@ public class OpenAISettingsForm { public void resetForm() { var state = OpenAISettings.getCurrentState(); - apiKeyField.setText(OpenAICredentialManager.getInstance().getCredential()); + apiKeyField.setText(CredentialsStore.INSTANCE.getCredential(OPENAI_API_KEY)); completionModelComboBox.setSelectedItem( OpenAIChatCompletionModel.findByCode(state.getModel())); organizationField.setText(state.getOrganization()); diff --git a/src/main/java/ee/carlrobert/codegpt/settings/service/you/YouSettingsForm.java b/src/main/java/ee/carlrobert/codegpt/settings/service/you/YouSettingsForm.java index d0b1e920..ccaa5835 100644 --- a/src/main/java/ee/carlrobert/codegpt/settings/service/you/YouSettingsForm.java +++ b/src/main/java/ee/carlrobert/codegpt/settings/service/you/YouSettingsForm.java @@ -1,5 +1,6 @@ package ee.carlrobert.codegpt.settings.service.you; +import static ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.YOU_ACCOUNT_PASSWORD; import static ee.carlrobert.codegpt.ui.UIUtil.withEmptyLeftBorder; import com.intellij.openapi.Disposable; @@ -23,7 +24,8 @@ import ee.carlrobert.codegpt.completions.you.auth.YouAuthenticationError; import ee.carlrobert.codegpt.completions.you.auth.YouAuthenticationService; import ee.carlrobert.codegpt.completions.you.auth.response.YouAuthenticationResponse; import ee.carlrobert.codegpt.completions.you.auth.response.YouUser; -import ee.carlrobert.codegpt.credentials.YouCredentialManager; +import ee.carlrobert.codegpt.credentials.CredentialsStore; +import ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey; import ee.carlrobert.codegpt.ui.UIUtil; import java.awt.BorderLayout; import java.awt.FlowLayout; @@ -51,7 +53,7 @@ public class YouSettingsForm extends JPanel { passwordField = new JBPasswordField(); passwordField.setColumns(25); if (!settings.getEmail().isEmpty()) { - passwordField.setText(YouCredentialManager.getInstance().getCredential()); + passwordField.setText(CredentialsStore.INSTANCE.getCredential(YOU_ACCOUNT_PASSWORD)); } signInButton = new JButton(CodeGPTBundle.get("settingsConfigurable.service.you.signIn.label")); signUpTextPane = createSignUpTextPane(); @@ -255,7 +257,9 @@ public class YouSettingsForm extends JPanel { var email = emailField.getText(); var password = passwordField.getPassword(); YouSettings.getCurrentState().setEmail(email); - YouCredentialManager.getInstance().setCredential(new String(password)); + CredentialsStore.INSTANCE.setCredential( + CredentialKey.YOU_ACCOUNT_PASSWORD, + new String(password)); refreshView(createUserInformationPanel(authenticationResponse.getData().getUser())); }); } diff --git a/src/main/kotlin/ee/carlrobert/codegpt/CodeGPTProjectActivity.kt b/src/main/kotlin/ee/carlrobert/codegpt/CodeGPTProjectActivity.kt index 025edae4..f8cfc21e 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/CodeGPTProjectActivity.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/CodeGPTProjectActivity.kt @@ -10,7 +10,9 @@ import ee.carlrobert.codegpt.completions.you.auth.AuthenticationHandler import ee.carlrobert.codegpt.completions.you.auth.YouAuthenticationError import ee.carlrobert.codegpt.completions.you.auth.YouAuthenticationService import ee.carlrobert.codegpt.completions.you.auth.response.YouAuthenticationResponse -import ee.carlrobert.codegpt.credentials.YouCredentialManager +import ee.carlrobert.codegpt.credentials.CredentialsStore +import ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey +import ee.carlrobert.codegpt.credentials.CredentialsStore.getCredential import ee.carlrobert.codegpt.settings.service.you.YouSettings import ee.carlrobert.codegpt.ui.OverlayUtil @@ -18,6 +20,7 @@ class CodeGPTProjectActivity : ProjectActivity { override suspend fun execute(project: Project) { EditorActionsUtil.refreshActions() + CredentialsStore.loadAll() if (YouUserManager.getInstance().authenticationResponse == null) { ApplicationManager.getApplication() @@ -27,8 +30,8 @@ class CodeGPTProjectActivity : ProjectActivity { private fun handleYouServiceAuthentication() { val settings = YouSettings.getCurrentState() - val password = YouCredentialManager.getInstance().credential - if (settings.email.isNotEmpty() && password != null && password.isNotEmpty()) { + val password = getCredential(CredentialKey.YOU_ACCOUNT_PASSWORD) + if (settings.email.isNotEmpty() && !password.isNullOrEmpty()) { YouAuthenticationService.getInstance() .signInAsync(settings.email, password, object : AuthenticationHandler { override fun handleAuthenticated(authenticationResponse: YouAuthenticationResponse) { diff --git a/src/main/kotlin/ee/carlrobert/codegpt/credentials/CredentialsStore.kt b/src/main/kotlin/ee/carlrobert/codegpt/credentials/CredentialsStore.kt new file mode 100644 index 00000000..1a97fc62 --- /dev/null +++ b/src/main/kotlin/ee/carlrobert/codegpt/credentials/CredentialsStore.kt @@ -0,0 +1,36 @@ +package ee.carlrobert.codegpt.credentials + +import com.intellij.credentialStore.CredentialAttributes +import com.intellij.credentialStore.generateServiceName +import com.intellij.ide.passwordSafe.PasswordSafe + +object CredentialsStore { + + private val credentialsMap = mutableMapOf() + + fun loadAll() { + CredentialKey.values().forEach { + val credentialAttributes = CredentialAttributes(generateServiceName("CodeGPT", it.name)) + val password = PasswordSafe.instance.getPassword(credentialAttributes) + setCredential(it, password) + } + } + + fun getCredential(key: CredentialKey): String? = credentialsMap[key] + + fun setCredential(key: CredentialKey, password: String?) { + credentialsMap[key] = password + } + + fun isCredentialSet(key: CredentialKey): Boolean = !getCredential(key).isNullOrEmpty() + + enum class CredentialKey { + OPENAI_API_KEY, + CUSTOM_SERVICE_API_KEY, + ANTHROPIC_API_KEY, + AZURE_OPENAI_API_KEY, + AZURE_ACTIVE_DIRECTORY_TOKEN, + YOU_ACCOUNT_PASSWORD, + LLAMA_API_KEY + } +} \ No newline at end of file diff --git a/src/test/java/ee/carlrobert/codegpt/completions/CompletionRequestProviderTest.java b/src/test/java/ee/carlrobert/codegpt/completions/CompletionRequestProviderTest.java index e8f8dc1b..21cb1054 100644 --- a/src/test/java/ee/carlrobert/codegpt/completions/CompletionRequestProviderTest.java +++ b/src/test/java/ee/carlrobert/codegpt/completions/CompletionRequestProviderTest.java @@ -6,7 +6,8 @@ import static org.assertj.core.groups.Tuple.tuple; import ee.carlrobert.codegpt.conversations.ConversationService; import ee.carlrobert.codegpt.conversations.message.Message; -import ee.carlrobert.codegpt.credentials.OpenAICredentialManager; +import ee.carlrobert.codegpt.credentials.CredentialsStore; +import ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey; import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings; import ee.carlrobert.llm.client.openai.completion.OpenAIChatCompletionModel; import testsupport.IntegrationTest; @@ -14,7 +15,7 @@ import testsupport.IntegrationTest; public class CompletionRequestProviderTest extends IntegrationTest { public void testChatCompletionRequestWithSystemPromptOverride() { - OpenAICredentialManager.getInstance().setCredential("TEST_API_KEY"); + CredentialsStore.INSTANCE.setCredential(CredentialKey.OPENAI_API_KEY, "TEST_API_KEY"); ConfigurationSettings.getCurrentState().setSystemPrompt("TEST_SYSTEM_PROMPT"); var conversation = ConversationService.getInstance().startConversation(); var firstMessage = createDummyMessage(500); diff --git a/src/test/java/testsupport/mixin/ShortcutsTestMixin.java b/src/test/java/testsupport/mixin/ShortcutsTestMixin.java index fd02bb73..c6f19be6 100644 --- a/src/test/java/testsupport/mixin/ShortcutsTestMixin.java +++ b/src/test/java/testsupport/mixin/ShortcutsTestMixin.java @@ -1,7 +1,9 @@ package testsupport.mixin; -import ee.carlrobert.codegpt.credentials.AzureCredentialsManager; -import ee.carlrobert.codegpt.credentials.OpenAICredentialManager; +import static ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.AZURE_OPENAI_API_KEY; +import static ee.carlrobert.codegpt.credentials.CredentialsStore.CredentialKey.OPENAI_API_KEY; + +import ee.carlrobert.codegpt.credentials.CredentialsStore; import ee.carlrobert.codegpt.settings.GeneralSettings; import ee.carlrobert.codegpt.settings.service.ServiceType; import ee.carlrobert.codegpt.settings.service.azure.AzureSettings; @@ -12,13 +14,13 @@ public interface ShortcutsTestMixin { default void useOpenAIService() { GeneralSettings.getCurrentState().setSelectedService(ServiceType.OPENAI); - OpenAICredentialManager.getInstance().setCredential("TEST_API_KEY"); + CredentialsStore.INSTANCE.setCredential(OPENAI_API_KEY, "TEST_API_KEY"); OpenAISettings.getCurrentState().setModel("gpt-4"); } default void useAzureService() { GeneralSettings.getCurrentState().setSelectedService(ServiceType.AZURE); - AzureCredentialsManager.getInstance().setApiKey("TEST_API_KEY"); + CredentialsStore.INSTANCE.setCredential(AZURE_OPENAI_API_KEY, "TEST_API_KEY"); var azureSettings = AzureSettings.getCurrentState(); azureSettings.setResourceName("TEST_RESOURCE_NAME"); azureSettings.setApiVersion("TEST_API_VERSION");