feat: add more specific component type to user-agent header (#10457)

In order to allow the portal to more easily classify, what kind of
component is connecting, we extend the `get_user_agent` header to
include a component type instead of the generic `connlib/`.

---------

Signed-off-by: Thomas Eizinger <thomas@eizinger.io>
Co-authored-by: Jamil <jamilbk@users.noreply.github.com>
This commit is contained in:
Thomas Eizinger
2025-09-26 00:18:36 +00:00
committed by GitHub
parent da768d6a70
commit 685acdac3a
11 changed files with 66 additions and 12 deletions

View File

@@ -5,6 +5,11 @@ defmodule Domain.Version do
|> Enum.find_value(fn
"relay/" <> version -> version
"connlib/" <> version -> version
"headless-client/" <> version -> version
"gui-client/" <> version -> version
"apple-client/" <> version -> version
"android-client/" <> version -> version
"gateway/" <> version -> version
_ -> nil
end)
|> case do

View File

@@ -0,0 +1,42 @@
defmodule Domain.VersionTest do
use ExUnit.Case, async: true
describe "fetch_version" do
test "can decode linux headless-client version" do
assert Domain.Version.fetch_version("Fedora/42.0.0 headless-client/1.4.5 (arm64; 24.1.0)") ==
{:ok, "1.4.5"}
end
test "can decode windows headless-client version" do
assert Domain.Version.fetch_version(
"Windows/10.0.22631 headless-client/1.4.5 (arm64; 24.1.0)"
) ==
{:ok, "1.4.5"}
end
test "can decode apple-client version" do
assert Domain.Version.fetch_version("Mac OS/15.1.1 apple-client/1.4.5 (arm64; 24.1.0)") ==
{:ok, "1.4.5"}
end
test "can decode android-client version" do
assert Domain.Version.fetch_version("Android/14 android-client/1.4.5 (arm64; 24.1.0)") ==
{:ok, "1.4.5"}
end
test "can decode windows gui-client version" do
assert Domain.Version.fetch_version("Windows/10.0.22631 gui-client/1.4.5 (arm64; 24.1.0)") ==
{:ok, "1.4.5"}
end
test "can decode linux gui-client version" do
assert Domain.Version.fetch_version("Fedora/42.0.0 gui-client/1.4.5 (arm64; 24.1.0)") ==
{:ok, "1.4.5"}
end
test "can decode gateway version" do
assert Domain.Version.fetch_version("Fedora/42.0.0 gateway/1.4.5 (arm64; 24.1.0)") ==
{:ok, "1.4.5"}
end
end
end

View File

@@ -287,7 +287,11 @@ impl WrappedSession {
let portal = PhoenixChannel::disconnected(
Secret::new(url),
get_user_agent(os_version_override, env!("CARGO_PKG_VERSION")),
get_user_agent(
os_version_override,
"apple-client",
env!("CARGO_PKG_VERSION"),
),
"client",
(),
|| {

View File

@@ -268,7 +268,7 @@ fn connect(
let portal = PhoenixChannel::disconnected(
Secret::new(url),
get_user_agent(os_version, platform::VERSION),
get_user_agent(os_version, platform::COMPONENT, platform::VERSION),
"client",
(),
|| {

View File

@@ -8,6 +8,7 @@ mod tun;
pub const RELEASE: &str = "connlib-android@1.5.2";
// mark:next-android-version
pub const VERSION: &str = "1.5.2";
pub const COMPONENT: &str = "android-client";
/// We have valid use cases for headless Android clients
/// (IoT devices, point-of-sale devices, etc), so try to reconnect for 30 days.

View File

@@ -4,6 +4,7 @@ use firezone_telemetry::Dsn;
pub const RELEASE: &str = "";
pub const VERSION: &str = "";
pub const COMPONENT: &str = "";
pub const DSN: Dsn = firezone_telemetry::TESTING;

View File

@@ -1,6 +1,8 @@
pub fn get_user_agent(os_version_override: Option<String>, app_version: &str) -> String {
const LIB_NAME: &str = "connlib";
pub fn get_user_agent(
os_version_override: Option<String>,
component_name: &str,
app_version: &str,
) -> String {
// Note: we could switch to sys-info and get the hostname
// but we lose the arch
// and neither of the libraries provide the kernel version.
@@ -16,8 +18,7 @@ pub fn get_user_agent(os_version_override: Option<String>, app_version: &str) ->
let os_version = os_version_override.unwrap_or(info.version().to_string());
let additional_info = additional_info();
let lib_name = LIB_NAME;
format!("{os_type}/{os_version} {lib_name}/{app_version}{additional_info}")
format!("{os_type}/{os_version} {component_name}/{app_version}{additional_info}")
}
fn additional_info() -> String {

View File

@@ -182,7 +182,7 @@ async fn try_main(cli: Cli, telemetry: &mut Telemetry) -> Result<()> {
);
let portal = PhoenixChannel::disconnected(
Secret::new(login),
get_user_agent(None, env!("CARGO_PKG_VERSION")),
get_user_agent(None, "gateway", env!("CARGO_PKG_VERSION")),
PHOENIX_TOPIC,
(),
|| {

View File

@@ -620,7 +620,7 @@ impl<'a> Handler<'a> {
// Synchronous DNS resolution here
let portal = PhoenixChannel::disconnected(
Secret::new(url),
get_user_agent(None, env!("CARGO_PKG_VERSION")),
get_user_agent(None, "gui-client", env!("CARGO_PKG_VERSION")),
"client",
(),
|| {

View File

@@ -327,7 +327,7 @@ fn try_main() -> Result<()> {
// When running interactively, it is useful for the user to see that we can't reach the portal.
let portal = PhoenixChannel::disconnected(
Secret::new(url),
get_user_agent(None, env!("CARGO_PKG_VERSION")),
get_user_agent(None, "headless-client", env!("CARGO_PKG_VERSION")),
"client",
(),
move || {

View File

@@ -12,7 +12,7 @@ use firezone_relay::{
};
use firezone_telemetry::{RELAY_DSN, Telemetry};
use futures::{FutureExt, future};
use phoenix_channel::{Event, LoginUrl, NoParams, PhoenixChannel};
use phoenix_channel::{Event, LoginUrl, NoParams, PhoenixChannel, get_user_agent};
use rand::rngs::StdRng;
use rand::{Rng, SeedableRng};
use secrecy::{ExposeSecret, Secret, SecretString};
@@ -240,7 +240,7 @@ async fn try_main(args: Args) -> Result<()> {
let mut channel = PhoenixChannel::disconnected(
Secret::new(login),
format!("relay/{}", env!("CARGO_PKG_VERSION")),
get_user_agent(None, "relay", env!("CARGO_PKG_VERSION")),
"relay",
JoinMessage {
stamp_secret: server.auth_secret().expose_secret().to_string(),