summaryrefslogtreecommitdiff
path: root/cli/lsp
diff options
context:
space:
mode:
authorKitson Kelly <me@kitsonkelly.com>2022-01-24 11:27:52 +1100
committerGitHub <noreply@github.com>2022-01-24 11:27:52 +1100
commit3ec248cff8fff1a41c2b2ad5301e7aa3db00c6a8 (patch)
tree549b791b6d9718a51d3f7c8258e076beafab64df /cli/lsp
parent3959d9f2d285bd45beb34074cf61090e2c4976dc (diff)
fix(lsp): respect DENO_CERT and other options related to TLS certs (#13467)
Fixes #13437
Diffstat (limited to 'cli/lsp')
-rw-r--r--cli/lsp/cache.rs6
-rw-r--r--cli/lsp/config.rs16
-rw-r--r--cli/lsp/language_server.rs62
-rw-r--r--cli/lsp/registries.rs54
-rw-r--r--cli/lsp/repl.rs3
5 files changed, 107 insertions, 34 deletions
diff --git a/cli/lsp/cache.rs b/cli/lsp/cache.rs
index 562ad78b0..e21bcff2d 100644
--- a/cli/lsp/cache.rs
+++ b/cli/lsp/cache.rs
@@ -33,6 +33,9 @@ impl CacheServer {
maybe_cache_path: Option<PathBuf>,
maybe_import_map: Option<Arc<ImportMap>>,
maybe_config_file: Option<ConfigFile>,
+ maybe_ca_stores: Option<Vec<String>>,
+ maybe_ca_file: Option<String>,
+ unsafely_ignore_certificate_errors: Option<Vec<String>>,
) -> Self {
let (tx, mut rx) = mpsc::unbounded_channel::<Request>();
let _join_handle = thread::spawn(move || {
@@ -40,6 +43,9 @@ impl CacheServer {
runtime.block_on(async {
let ps = ProcState::build(Flags {
cache_path: maybe_cache_path,
+ ca_stores: maybe_ca_stores,
+ ca_file: maybe_ca_file,
+ unsafely_ignore_certificate_errors,
..Default::default()
})
.await
diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs
index 89924a22a..37558e1b7 100644
--- a/cli/lsp/config.rs
+++ b/cli/lsp/config.rs
@@ -154,6 +154,10 @@ pub struct WorkspaceSettings {
/// cache/DENO_DIR for the language server.
pub cache: Option<String>,
+ /// Override the default stores used to validate certificates. This overrides
+ /// the environment variable `DENO_TLS_CA_STORE` if present.
+ pub certificate_stores: Option<Vec<String>>,
+
/// An option that points to a path string of the config file to apply to
/// code within the workspace.
pub config: Option<String>,
@@ -179,6 +183,15 @@ pub struct WorkspaceSettings {
#[serde(default)]
pub suggest: CompletionSettings,
+ /// An option which sets the cert file to use when attempting to fetch remote
+ /// resources. This overrides `DENO_CERT` if present.
+ pub tls_certificate: Option<String>,
+
+ /// An option, if set, will unsafely ignore certificate errors when fetching
+ /// remote resources.
+ #[serde(default)]
+ pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
+
#[serde(default)]
pub unstable: bool,
}
@@ -485,6 +498,7 @@ mod tests {
WorkspaceSettings {
enable: false,
cache: None,
+ certificate_stores: None,
config: None,
import_map: None,
code_lens: CodeLensSettings {
@@ -505,6 +519,8 @@ mod tests {
hosts: HashMap::new(),
}
},
+ tls_certificate: None,
+ unsafely_ignore_certificate_errors: None,
unstable: false,
}
);
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs
index e33ffc93a..5ad0c17a6 100644
--- a/cli/lsp/language_server.rs
+++ b/cli/lsp/language_server.rs
@@ -48,7 +48,8 @@ use super::lsp_custom;
use super::parent_process_checker;
use super::performance::Performance;
use super::refactor;
-use super::registries;
+use super::registries::ModuleRegistry;
+use super::registries::ModuleRegistryOptions;
use super::text;
use super::tsc;
use super::tsc::AssetDocument;
@@ -96,7 +97,7 @@ pub(crate) struct Inner {
/// on disk or "open" within the client.
pub(crate) documents: Documents,
/// Handles module registries, which allow discovery of modules
- module_registries: registries::ModuleRegistry,
+ module_registries: ModuleRegistry,
/// The path to the module registries cache
module_registries_location: PathBuf,
/// An optional path to the DENO_DIR which has been specified in the client
@@ -139,8 +140,11 @@ impl Inner {
let dir = deno_dir::DenoDir::new(maybe_custom_root)
.expect("could not access DENO_DIR");
let module_registries_location = dir.root.join(REGISTRIES_PATH);
- let module_registries =
- registries::ModuleRegistry::new(&module_registries_location);
+ let module_registries = ModuleRegistry::new(
+ &module_registries_location,
+ ModuleRegistryOptions::default(),
+ )
+ .expect("could not create module registries");
let location = dir.root.join(CACHE_PATH);
let documents = Documents::new(&location);
let performance = Arc::new(Performance::default());
@@ -425,11 +429,23 @@ impl Inner {
let maybe_custom_root = maybe_cache_path
.clone()
.or_else(|| env::var("DENO_DIR").map(String::into).ok());
- let dir = deno_dir::DenoDir::new(maybe_custom_root)
- .expect("could not access DENO_DIR");
+ let dir = deno_dir::DenoDir::new(maybe_custom_root)?;
let module_registries_location = dir.root.join(REGISTRIES_PATH);
- self.module_registries =
- registries::ModuleRegistry::new(&module_registries_location);
+ let workspace_settings = self.config.get_workspace_settings();
+ let maybe_root_path = self
+ .root_uri
+ .as_ref()
+ .and_then(|uri| fs_util::specifier_to_file_path(uri).ok());
+ self.module_registries = ModuleRegistry::new(
+ &module_registries_location,
+ ModuleRegistryOptions {
+ maybe_root_path,
+ maybe_ca_stores: workspace_settings.certificate_stores.clone(),
+ maybe_ca_file: workspace_settings.tls_certificate.clone(),
+ unsafely_ignore_certificate_errors: workspace_settings
+ .unsafely_ignore_certificate_errors,
+ },
+ )?;
self.module_registries_location = module_registries_location;
self.documents.set_location(dir.root.join(CACHE_PATH));
self.maybe_cache_path = maybe_cache_path;
@@ -496,14 +512,23 @@ impl Inner {
async fn update_registries(&mut self) -> Result<(), AnyError> {
let mark = self.performance.mark("update_registries", None::<()>);
- for (registry, enabled) in self
- .config
- .get_workspace_settings()
- .suggest
- .imports
- .hosts
- .iter()
- {
+ let workspace_settings = self.config.get_workspace_settings();
+ let maybe_root_path = self
+ .root_uri
+ .as_ref()
+ .and_then(|uri| fs_util::specifier_to_file_path(uri).ok());
+ self.module_registries = ModuleRegistry::new(
+ &self.module_registries_location,
+ ModuleRegistryOptions {
+ maybe_root_path,
+ maybe_ca_stores: workspace_settings.certificate_stores.clone(),
+ maybe_ca_file: workspace_settings.tls_certificate.clone(),
+ unsafely_ignore_certificate_errors: workspace_settings
+ .unsafely_ignore_certificate_errors
+ .clone(),
+ },
+ )?;
+ for (registry, enabled) in workspace_settings.suggest.imports.hosts.iter() {
if *enabled {
lsp_log!("Enabling import suggestions for: {}", registry);
self.module_registries.enable(registry).await?;
@@ -2583,6 +2608,9 @@ impl Inner {
self.maybe_cache_path.clone(),
self.maybe_import_map.clone(),
self.maybe_config_file.clone(),
+ None,
+ None,
+ None,
)
.await,
);
@@ -2616,8 +2644,6 @@ impl Inner {
error!("Unable to remove registries cache: {}", err);
LspError::internal_error()
})?;
- self.module_registries =
- registries::ModuleRegistry::new(&self.module_registries_location);
self.update_registries().await.map_err(|err| {
error!("Unable to update registries: {}", err);
LspError::internal_error()
diff --git a/cli/lsp/registries.rs b/cli/lsp/registries.rs
index 418c19fe3..0b8a4240b 100644
--- a/cli/lsp/registries.rs
+++ b/cli/lsp/registries.rs
@@ -12,6 +12,7 @@ use super::path_to_regex::StringOrVec;
use super::path_to_regex::Token;
use crate::deno_dir;
+use crate::file_fetcher::get_root_cert_store;
use crate::file_fetcher::CacheSetting;
use crate::file_fetcher::FileFetcher;
use crate::http_cache::HttpCache;
@@ -37,6 +38,7 @@ use once_cell::sync::Lazy;
use regex::Regex;
use std::collections::HashMap;
use std::path::Path;
+use std::path::PathBuf;
const CONFIG_PATH: &str = "/.well-known/deno-import-intellisense.json";
const COMPONENT: &percent_encoding::AsciiSet = &percent_encoding::CONTROLS
@@ -406,11 +408,19 @@ enum VariableItems {
List(VariableItemsList),
}
+#[derive(Debug, Default)]
+pub(crate) struct ModuleRegistryOptions {
+ pub maybe_root_path: Option<PathBuf>,
+ pub maybe_ca_stores: Option<Vec<String>>,
+ pub maybe_ca_file: Option<String>,
+ pub unsafely_ignore_certificate_errors: Option<Vec<String>>,
+}
+
/// A structure which holds the information about currently configured module
/// registries and can provide completion information for URLs that match
/// one of the enabled registries.
#[derive(Debug, Clone)]
-pub struct ModuleRegistry {
+pub(crate) struct ModuleRegistry {
origins: HashMap<String, Vec<RegistryConfiguration>>,
file_fetcher: FileFetcher,
}
@@ -422,29 +432,35 @@ impl Default for ModuleRegistry {
// custom root.
let dir = deno_dir::DenoDir::new(None).unwrap();
let location = dir.root.join("registries");
- Self::new(&location)
+ Self::new(&location, ModuleRegistryOptions::default()).unwrap()
}
}
impl ModuleRegistry {
- pub fn new(location: &Path) -> Self {
+ pub fn new(
+ location: &Path,
+ options: ModuleRegistryOptions,
+ ) -> Result<Self, AnyError> {
let http_cache = HttpCache::new(location);
+ let root_cert_store = Some(get_root_cert_store(
+ options.maybe_root_path,
+ options.maybe_ca_stores,
+ options.maybe_ca_file,
+ )?);
let mut file_fetcher = FileFetcher::new(
http_cache,
CacheSetting::RespectHeaders,
true,
- None,
+ root_cert_store,
BlobStore::default(),
- None,
- )
- .context("Error creating file fetcher in module registry.")
- .unwrap();
+ options.unsafely_ignore_certificate_errors,
+ )?;
file_fetcher.set_download_log_level(super::logging::lsp_log_level());
- Self {
+ Ok(Self {
origins: HashMap::new(),
file_fetcher,
- }
+ })
}
fn complete_literal(
@@ -1200,7 +1216,8 @@ mod tests {
let _g = test_util::http_server();
let temp_dir = TempDir::new().expect("could not create tmp");
let location = temp_dir.path().join("registries");
- let mut module_registry = ModuleRegistry::new(&location);
+ let mut module_registry =
+ ModuleRegistry::new(&location, ModuleRegistryOptions::default()).unwrap();
module_registry
.enable("http://localhost:4545/")
.await
@@ -1260,7 +1277,8 @@ mod tests {
let _g = test_util::http_server();
let temp_dir = TempDir::new().expect("could not create tmp");
let location = temp_dir.path().join("registries");
- let mut module_registry = ModuleRegistry::new(&location);
+ let mut module_registry =
+ ModuleRegistry::new(&location, ModuleRegistryOptions::default()).unwrap();
module_registry
.enable("http://localhost:4545/")
.await
@@ -1482,7 +1500,8 @@ mod tests {
let _g = test_util::http_server();
let temp_dir = TempDir::new().expect("could not create tmp");
let location = temp_dir.path().join("registries");
- let mut module_registry = ModuleRegistry::new(&location);
+ let mut module_registry =
+ ModuleRegistry::new(&location, ModuleRegistryOptions::default()).unwrap();
module_registry
.enable_custom("http://localhost:4545/lsp/registries/deno-import-intellisense-key-first.json")
.await
@@ -1551,7 +1570,8 @@ mod tests {
let _g = test_util::http_server();
let temp_dir = TempDir::new().expect("could not create tmp");
let location = temp_dir.path().join("registries");
- let mut module_registry = ModuleRegistry::new(&location);
+ let mut module_registry =
+ ModuleRegistry::new(&location, ModuleRegistryOptions::default()).unwrap();
module_registry
.enable_custom("http://localhost:4545/lsp/registries/deno-import-intellisense-complex.json")
.await
@@ -1601,7 +1621,8 @@ mod tests {
let _g = test_util::http_server();
let temp_dir = TempDir::new().expect("could not create tmp");
let location = temp_dir.path().join("registries");
- let module_registry = ModuleRegistry::new(&location);
+ let module_registry =
+ ModuleRegistry::new(&location, ModuleRegistryOptions::default()).unwrap();
let result = module_registry.check_origin("http://localhost:4545").await;
assert!(result.is_ok());
}
@@ -1611,7 +1632,8 @@ mod tests {
let _g = test_util::http_server();
let temp_dir = TempDir::new().expect("could not create tmp");
let location = temp_dir.path().join("registries");
- let module_registry = ModuleRegistry::new(&location);
+ let module_registry =
+ ModuleRegistry::new(&location, ModuleRegistryOptions::default()).unwrap();
let result = module_registry.check_origin("https://deno.com").await;
assert!(result.is_err());
let err = result.unwrap_err().to_string();
diff --git a/cli/lsp/repl.rs b/cli/lsp/repl.rs
index b4bc1daf7..0a2603298 100644
--- a/cli/lsp/repl.rs
+++ b/cli/lsp/repl.rs
@@ -277,11 +277,14 @@ pub fn get_repl_workspace_settings() -> WorkspaceSettings {
WorkspaceSettings {
enable: true,
config: None,
+ certificate_stores: None,
cache: None,
import_map: None,
code_lens: Default::default(),
internal_debug: false,
lint: false,
+ tls_certificate: None,
+ unsafely_ignore_certificate_errors: None,
unstable: false,
suggest: CompletionSettings {
complete_function_calls: false,