Deployment and lifecycle management for Nix
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: channels token authentication for client daemon

+355 -38
+6
.envrc
··· 10 10 export RELEASE_COOKIE=$(cat $RELEASE_COOKIE_FILE) 11 11 12 12 export ERL_AFLAGS="-kernel shell_history enabled -kernel shell_history_file_bytes 1024000" 13 + 14 + export SOWER_BOOTSTRAP_TOKEN_FILE="$PWD/.bootstrap.token" 15 + if [ ! -f "$SOWER_BOOTSTRAP_TOKEN_FILE" ]; then 16 + echo "Creating development bootstrap token file" 17 + dd if=/dev/urandom bs=1 count=64 | hexdump -e '64/1 "%02x"' >"$SOWER_BOOTSTRAP_TOKEN_FILE" 18 + fi
+1
.gitignore
··· 38 38 target/ 39 39 data/ 40 40 .nixos-test-history 41 + .bootstrap.token
+182
Cargo.lock
··· 18 18 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 19 20 20 [[package]] 21 + name = "aho-corasick" 22 + version = "1.1.3" 23 + source = "registry+https://github.com/rust-lang/crates.io-index" 24 + checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 25 + dependencies = [ 26 + "memchr", 27 + ] 28 + 29 + [[package]] 21 30 name = "anstream" 22 31 version = "0.6.14" 23 32 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 274 283 ] 275 284 276 285 [[package]] 286 + name = "crc32fast" 287 + version = "1.4.0" 288 + source = "registry+https://github.com/rust-lang/crates.io-index" 289 + checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" 290 + dependencies = [ 291 + "cfg-if", 292 + ] 293 + 294 + [[package]] 277 295 name = "crypto-common" 278 296 version = "0.1.6" 279 297 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 290 308 checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" 291 309 292 310 [[package]] 311 + name = "deranged" 312 + version = "0.3.11" 313 + source = "registry+https://github.com/rust-lang/crates.io-index" 314 + checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" 315 + dependencies = [ 316 + "powerfmt", 317 + ] 318 + 319 + [[package]] 293 320 name = "digest" 294 321 version = "0.10.7" 295 322 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 315 342 checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 316 343 317 344 [[package]] 345 + name = "flate2" 346 + version = "1.0.30" 347 + source = "registry+https://github.com/rust-lang/crates.io-index" 348 + checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" 349 + dependencies = [ 350 + "crc32fast", 351 + "miniz_oxide", 352 + ] 353 + 354 + [[package]] 318 355 name = "flexstr" 319 356 version = "0.9.2" 320 357 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 331 368 checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 332 369 333 370 [[package]] 371 + name = "foreign-types" 372 + version = "0.3.2" 373 + source = "registry+https://github.com/rust-lang/crates.io-index" 374 + checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 375 + dependencies = [ 376 + "foreign-types-shared", 377 + ] 378 + 379 + [[package]] 380 + name = "foreign-types-shared" 381 + version = "0.1.1" 382 + source = "registry+https://github.com/rust-lang/crates.io-index" 383 + checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 384 + 385 + [[package]] 334 386 name = "form_urlencoded" 335 387 version = "1.2.1" 336 388 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 638 690 checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 639 691 640 692 [[package]] 693 + name = "josekit" 694 + version = "0.8.6" 695 + source = "registry+https://github.com/rust-lang/crates.io-index" 696 + checksum = "0953340cf63354cec4a385f1fbcb3f409a5823778cae236078892f6030ed4565" 697 + dependencies = [ 698 + "anyhow", 699 + "base64 0.21.7", 700 + "flate2", 701 + "once_cell", 702 + "openssl", 703 + "regex", 704 + "serde", 705 + "serde_json", 706 + "thiserror", 707 + "time", 708 + ] 709 + 710 + [[package]] 641 711 name = "js-sys" 642 712 version = "0.3.69" 643 713 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 729 799 ] 730 800 731 801 [[package]] 802 + name = "num-conv" 803 + version = "0.1.0" 804 + source = "registry+https://github.com/rust-lang/crates.io-index" 805 + checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 806 + 807 + [[package]] 732 808 name = "num_cpus" 733 809 version = "1.16.0" 734 810 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 760 836 checksum = "6c548d5c78976f6955d72d0ced18c48ca07030f7a1d4024529fedd7c1c01b29c" 761 837 762 838 [[package]] 839 + name = "openssl" 840 + version = "0.10.64" 841 + source = "registry+https://github.com/rust-lang/crates.io-index" 842 + checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" 843 + dependencies = [ 844 + "bitflags 2.5.0", 845 + "cfg-if", 846 + "foreign-types", 847 + "libc", 848 + "once_cell", 849 + "openssl-macros", 850 + "openssl-sys", 851 + ] 852 + 853 + [[package]] 854 + name = "openssl-macros" 855 + version = "0.1.1" 856 + source = "registry+https://github.com/rust-lang/crates.io-index" 857 + checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 858 + dependencies = [ 859 + "proc-macro2", 860 + "quote", 861 + "syn", 862 + ] 863 + 864 + [[package]] 763 865 name = "openssl-probe" 764 866 version = "0.1.5" 765 867 source = "registry+https://github.com/rust-lang/crates.io-index" 766 868 checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 869 + 870 + [[package]] 871 + name = "openssl-sys" 872 + version = "0.9.102" 873 + source = "registry+https://github.com/rust-lang/crates.io-index" 874 + checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" 875 + dependencies = [ 876 + "cc", 877 + "libc", 878 + "pkg-config", 879 + "vcpkg", 880 + ] 767 881 768 882 [[package]] 769 883 name = "overload" ··· 842 956 checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 843 957 844 958 [[package]] 959 + name = "pkg-config" 960 + version = "0.3.30" 961 + source = "registry+https://github.com/rust-lang/crates.io-index" 962 + checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 963 + 964 + [[package]] 965 + name = "powerfmt" 966 + version = "0.2.0" 967 + source = "registry+https://github.com/rust-lang/crates.io-index" 968 + checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 969 + 970 + [[package]] 845 971 name = "ppv-lite86" 846 972 version = "0.2.17" 847 973 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 905 1031 ] 906 1032 907 1033 [[package]] 1034 + name = "regex" 1035 + version = "1.10.4" 1036 + source = "registry+https://github.com/rust-lang/crates.io-index" 1037 + checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" 1038 + dependencies = [ 1039 + "aho-corasick", 1040 + "memchr", 1041 + "regex-automata", 1042 + "regex-syntax", 1043 + ] 1044 + 1045 + [[package]] 1046 + name = "regex-automata" 1047 + version = "0.4.6" 1048 + source = "registry+https://github.com/rust-lang/crates.io-index" 1049 + checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" 1050 + dependencies = [ 1051 + "aho-corasick", 1052 + "memchr", 1053 + "regex-syntax", 1054 + ] 1055 + 1056 + [[package]] 1057 + name = "regex-syntax" 1058 + version = "0.8.3" 1059 + source = "registry+https://github.com/rust-lang/crates.io-index" 1060 + checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" 1061 + 1062 + [[package]] 908 1063 name = "reqwest" 909 1064 version = "0.11.27" 910 1065 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1137 1292 source = "registry+https://github.com/rust-lang/crates.io-index" 1138 1293 checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" 1139 1294 dependencies = [ 1295 + "indexmap", 1140 1296 "itoa", 1141 1297 "ryu", 1142 1298 "serde", ··· 1228 1384 version = "0.2.0-dev" 1229 1385 dependencies = [ 1230 1386 "clap", 1387 + "josekit", 1231 1388 "nix", 1232 1389 "phoenix_channels_client", 1233 1390 "reqwest", ··· 1359 1516 ] 1360 1517 1361 1518 [[package]] 1519 + name = "time" 1520 + version = "0.3.36" 1521 + source = "registry+https://github.com/rust-lang/crates.io-index" 1522 + checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" 1523 + dependencies = [ 1524 + "deranged", 1525 + "num-conv", 1526 + "powerfmt", 1527 + "serde", 1528 + "time-core", 1529 + ] 1530 + 1531 + [[package]] 1532 + name = "time-core" 1533 + version = "0.1.2" 1534 + source = "registry+https://github.com/rust-lang/crates.io-index" 1535 + checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 1536 + 1537 + [[package]] 1362 1538 name = "tinyvec" 1363 1539 version = "1.6.0" 1364 1540 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1736 1912 version = "0.1.0" 1737 1913 source = "registry+https://github.com/rust-lang/crates.io-index" 1738 1914 checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 1915 + 1916 + [[package]] 1917 + name = "vcpkg" 1918 + version = "0.2.15" 1919 + source = "registry+https://github.com/rust-lang/crates.io-index" 1920 + checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1739 1921 1740 1922 [[package]] 1741 1923 name = "version_check"
+1
client/Cargo.toml
··· 7 7 8 8 [dependencies] 9 9 clap = { version = "4.5.1", features = ["derive", "color"] } 10 + josekit = "0.8.6" 10 11 nix = { version = "0.28.0", features = ["hostname"] } 11 12 phoenix_channels_client = { git = "https://github.com/liveview-native/phoenix-channels-client.git", version = "0.9.0" } 12 13 reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls"] }
+36 -1
client/src/main.rs
··· 18 18 action: Actions, 19 19 20 20 #[arg(long, short, global = true)] 21 + bootstrap_token_file: Option<PathBuf>, 22 + 23 + #[arg(long, short, global = true)] 21 24 config: Option<PathBuf>, 22 25 23 26 #[arg(long, short, global = true)] ··· 97 100 98 101 #[derive(Debug, Deserialize)] 99 102 pub struct Config { 103 + bootstrap_token: Option<String>, 104 + bootstrap_token_file: Option<PathBuf>, 100 105 reboot: Option<bool>, 101 106 mode: Option<ActivationMode>, 102 107 name: Option<String>, ··· 106 111 } 107 112 108 113 impl Config { 114 + pub fn bootstrap_token(self) -> Self { 115 + let bootstrap_token = fs::read_to_string(self.bootstrap_token_file.clone().unwrap()).ok(); 116 + if let Some(_) = &bootstrap_token { 117 + Self { 118 + bootstrap_token, 119 + ..self 120 + } 121 + } else { 122 + self 123 + } 124 + } 125 + 126 + pub fn bootstrap_token_file(self, bootstrap_token_file: Option<PathBuf>) -> Self { 127 + if let Some(_) = &bootstrap_token_file { 128 + Self { 129 + bootstrap_token_file, 130 + ..self 131 + } 132 + } else { 133 + self 134 + } 135 + } 136 + 109 137 pub fn name(self, name: Option<String>) -> Self { 110 138 if let Some(_) = &name { 111 139 Self { name, ..self } ··· 166 194 toml::from_str(&config_string).expect("failed to parse config file") 167 195 } 168 196 _ => Config { 197 + bootstrap_token: None, 198 + bootstrap_token_file: None, 169 199 reboot: None, 170 200 mode: None, 171 201 name: None, ··· 175 205 }; 176 206 177 207 // cli overrides config 178 - let config = config.name(cli.name).seed_type(cli.seed_type).url(cli.url); 208 + let config = config 209 + .name(cli.name) 210 + .seed_type(cli.seed_type) 211 + .url(cli.url) 212 + .bootstrap_token_file(cli.bootstrap_token_file) 213 + .bootstrap_token(); 179 214 180 215 let tree = Tree::new(&config).await?; 181 216
+60 -7
client/src/sower/daemon.rs
··· 3 3 use std::sync::Arc; 4 4 use std::time::Duration; 5 5 6 + use josekit::{ 7 + jws::{JwsHeader, HS256}, 8 + jwt::{self, JwtPayload}, 9 + JoseError, 10 + }; 6 11 use phoenix_channels_client::url::Url; 7 12 use phoenix_channels_client::{ 8 13 Channel, Event, EventPayload, EventsError, Payload, Socket, Topic, JSON, 9 14 }; 10 15 use serde_json::json; 11 - use tokio::signal; 12 - use tracing::info; 16 + use tokio::{signal, time}; 17 + use tracing::{debug, error, info}; 13 18 14 19 pub struct Daemon { 15 20 tree: Tree, ··· 23 28 let tree = Tree::new(config).await.expect("Failed to load tree"); 24 29 25 30 info!("Connecting to sower"); 26 - let url = Url::parse(&tree.sower.clone().unwrap().channels_url).unwrap(); 31 + let url = Url::parse_with_params( 32 + &tree.sower.clone().unwrap().channels_url, 33 + &[( 34 + "token", 35 + Self::sign_login_jwt(config.bootstrap_token.clone().unwrap(), &tree).unwrap(), 36 + )], 37 + ) 38 + .unwrap(); 27 39 let socket = Socket::spawn(url, None).unwrap(); 28 - socket.connect(Duration::from_secs(10)).await.unwrap(); 40 + match socket.connect(Duration::from_secs(10)).await { 41 + Ok(_) => info!("Connected"), 42 + Err(_) => panic!("Failed to connect"), 43 + } 29 44 30 - info!("Joining lobby tree:all"); 31 - let topic = Topic::from_string("tree:all".to_string()); 45 + let topic = Topic::from_string("client:all".to_string()); 46 + info!("Joining lobby {}", topic); 32 47 let channel = socket.channel(topic.clone(), None).await.unwrap(); 33 48 channel.join(Duration::from_secs(15)).await.unwrap(); 34 49 ··· 40 55 } 41 56 } 42 57 58 + fn sign_login_jwt(key: String, tree: &Tree) -> Result<String, JoseError> { 59 + let mut header = JwsHeader::new(); 60 + header.set_token_type("JWT"); 61 + header.set_algorithm("HS256"); 62 + 63 + let mut payload = JwtPayload::new(); 64 + payload.set_subject("client"); 65 + payload.set_claim("name", Some(json!(tree.name))).unwrap(); 66 + payload 67 + .set_claim("seed_type", Some(json!(tree.seed_type))) 68 + .unwrap(); 69 + 70 + let signer = HS256.signer_from_bytes(key)?; 71 + let jwt = jwt::encode_with_signer(&payload, &header, &signer)?; 72 + 73 + Ok(jwt) 74 + } 75 + 43 76 pub async fn login(&mut self) { 44 77 info!("Registering with sower"); 45 78 let Payload::JSONPayload { json } = self ··· 69 102 pub async fn run(&mut self) -> Result<(), std::io::Error> { 70 103 self.login().await; 71 104 72 - let events = self.lobby_channel.events(); 73 105 tokio::select! { 74 106 _ = signal::ctrl_c() => { 75 107 info!("Received shutdown") 76 108 }, 77 109 78 110 _ = async { 111 + let events = self.lobby_channel.events(); 112 + 79 113 info!("Listening for events"); 80 114 loop { 81 115 match events.event().await { ··· 94 128 eprintln!("{} events missed on channel {}", missed_event_count, self.lobby_topic); 95 129 } 96 130 }, 131 + } 132 + } 133 + } => {}, 134 + 135 + _ = async { 136 + info!("Starting submit loop"); 137 + let mut interval = time::interval(time::Duration::from_secs(5)); 138 + loop { 139 + interval.tick().await; 140 + debug!("tick"); 141 + let reply_payload = self.lobby_channel.call( 142 + Event::from_string("ping".to_string()), 143 + Payload::json_from_serialized(json!({ "token": "ok" }).to_string()).unwrap(), 144 + Duration::from_secs(5) 145 + ).await; 146 + 147 + match reply_payload { 148 + Ok(payload) => info!("{}", payload), 149 + Err(err) => error!("{}", err) 97 150 } 98 151 } 99 152 } => {}
+3
config/runtime.exs
··· 20 20 config :sower, SowerWeb.Endpoint, server: true 21 21 end 22 22 23 + config :sower, 24 + bootstrap_token: Sower.Application.credential!("SOWER_BOOTSTRAP_TOKEN_FILE") 25 + 23 26 if config_env() == :prod do 24 27 if System.get_env() |> Map.has_key?("SOWER_DATABASE_SOCKET") do 25 28 config :sower, Sower.Repo,
+2 -1
flake.nix
··· 93 93 nativeBuildInputs = [ 94 94 pkgs.fmt 95 95 pkgs.libgit2 96 + pkgs.openssl 97 + pkgs.pkg-config 96 98 ]; 97 99 }; 98 100 ··· 119 121 flake = { 120 122 nixosModules.sower = ./nix/nixos-module.nix; 121 123 homeModules.sower = ./nix/home-module.nix; 122 - 123 124 124 125 typhonProject = inputs.typhon.lib.gitea.mkProject { 125 126 instance = "git.junco.dev";
+31
lib/sower_web/client_channel.ex
··· 1 + defmodule SowerWeb.ClientChannel do 2 + use Phoenix.Channel 3 + 4 + def join("client:all", _message, socket) do 5 + {:ok, socket} 6 + end 7 + 8 + def join("client:" <> client_name, _params, _socket) do 9 + {:error, %{reason: "unauthorized"}} 10 + end 11 + 12 + def handle_in("register", %{"name" => name, "type" => type}, socket) do 13 + id = 14 + with {:ok, client} <- Sower.Tree.register(name, type) do 15 + client.id 16 + else 17 + {:error, _} -> Sower.Tree.find!(name, type) |> Map.get(:id) 18 + end 19 + 20 + {:reply, {:ok, id}, socket} 21 + end 22 + 23 + def handle_in("ping", %{"token" => token}, socket) do 24 + jwk = %{"kty" => "oct", "k" => :jose_base64url.encode("0123456789ABCDEF0123456789ABCDEF")} 25 + 26 + case JOSE.JWT.verify(jwk, token) do 27 + {true, jwt, _} -> {:reply, {:ok, "success"}, socket} 28 + _ -> {:reply, {:error, "unauthorized"}, socket} 29 + end 30 + end 31 + end
+11 -3
lib/sower_web/client_socket.ex
··· 1 1 defmodule SowerWeb.ClientSocket do 2 2 use Phoenix.Socket 3 3 4 - channel "tree:*", SowerWeb.TreeChannel 4 + channel("client:*", SowerWeb.ClientChannel) 5 5 6 6 @impl true 7 - def connect(_params, socket, _connect_info) do 8 - {:ok, socket} 7 + def connect(%{"token" => token}, socket, _connect_info) do 8 + jwk = %{ 9 + "kty" => "oct", 10 + "k" => :jose_base64url.encode(Application.fetch_env!(:sower, :bootstrap_token)) 11 + } 12 + 13 + case JOSE.JWT.verify(jwk, token) do 14 + {true, _jwt, _} -> {:ok, socket} 15 + _ -> {:error, "unauthorized"} 16 + end 9 17 end 10 18 11 19 @impl true
-22
lib/sower_web/tree_channel.ex
··· 1 - defmodule SowerWeb.TreeChannel do 2 - use Phoenix.Channel 3 - 4 - def join("tree:all", _message, socket) do 5 - {:ok, socket} 6 - end 7 - 8 - def join("tree:" <> tree_name, _params, _socket) do 9 - {:error, %{reason: "unauthorized"}} 10 - end 11 - 12 - def handle_in("register", %{"name" => name, "type" => type}, socket) do 13 - id = 14 - with {:ok, tree} <- Sower.Tree.register(name, type) do 15 - tree.id 16 - else 17 - {:error, _} -> Sower.Tree.find!(name, type) |> Map.get(:id) 18 - end 19 - 20 - {:reply, {:ok, id}, socket} 21 - end 22 - end
+1
mix.exs
··· 26 26 {:gettext, "~> 0.20"}, 27 27 {:hackney, "~> 1.8"}, 28 28 {:jason, "~> 1.2"}, 29 + {:jose, "~> 1.11"}, 29 30 {:makeup, "~> 1.1"}, 30 31 {:makeup_json, "~> 0.1.0"}, 31 32 {:open_api_spex, "~> 3.19"},
+1
mix.lock
··· 25 25 "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, 26 26 "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, 27 27 "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, 28 + "jose": {:hex, :jose, "1.11.10", "a903f5227417bd2a08c8a00a0cbcc458118be84480955e8d251297a425723f83", [:mix, :rebar3], [], "hexpm", "0d6cd36ff8ba174db29148fc112b5842186b68a90ce9fc2b3ec3afe76593e614"}, 28 29 "json_xema": {:hex, :json_xema, "0.6.2", "2af74c57f3f8dff8b74502d69d53f1ae7b6b236b477f30871c415ea8377a4c72", [:mix], [{:conv_case, "~> 0.2", [hex: :conv_case, repo: "hexpm", optional: false]}, {:xema, "~> 0.16", [hex: :xema, repo: "hexpm", optional: false]}], "hexpm", "50c84c537c95fcc76677f1f030af4aed188f538820fc488aeaa3f7dfe04d0edf"}, 29 30 "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, 30 31 "makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"},
+7 -4
nix/client-package.nix
··· 4 4 craneLib, 5 5 darwin, 6 6 libiconv, 7 + openssl, 7 8 rustTarget, 8 9 stdenv, 9 10 }: ··· 26 27 CARGO_BUILD_TARGET = rustTarget; 27 28 CARGO_BUILD_RUSTFLAGS = "-C target-feature=+crt-static"; 28 29 29 - buildInputs = lib.optionals stdenv.isDarwin [ 30 - libiconv 31 - darwin.apple_sdk.frameworks.SystemConfiguration 32 - ]; 30 + buildInputs = 31 + [ openssl ] 32 + ++ lib.optionals stdenv.isDarwin [ 33 + libiconv 34 + darwin.apple_sdk.frameworks.SystemConfiguration 35 + ]; 33 36 34 37 meta.mainProgram = "sower"; 35 38 }
+13
nix/mix.nix
··· 346 346 beamDeps = [ decimal ]; 347 347 }; 348 348 349 + jose = buildMix rec { 350 + name = "jose"; 351 + version = "1.11.10"; 352 + 353 + src = fetchHex { 354 + pkg = "jose"; 355 + version = "${version}"; 356 + sha256 = "0d6cd36ff8ba174db29148fc112b5842186b68a90ce9fc2b3ec3afe76593e614"; 357 + }; 358 + 359 + beamDeps = []; 360 + }; 361 + 349 362 json_xema = buildMix rec { 350 363 name = "json_xema"; 351 364 version = "0.6.2";