defmodule NPM.Registry.Token do @moduledoc """ Manages npm authentication tokens. Handles reading, validating, and masking auth tokens used for private registry access. """ @doc """ Reads the auth token from environment or .npmrc. """ @spec read :: String.t() | nil def read do NPM.Config.auth_token() || read_from_npmrc() end @doc """ Checks if a valid auth token is configured. """ @spec configured? :: boolean() def configured?, do: read() != nil @doc """ Masks a token for safe display. Shows only the first and last 4 characters. """ @spec mask(String.t()) :: String.t() def mask(token) when byte_size(token) <= 8, do: "****" def mask(token) do first = String.slice(token, 0, 4) last = String.slice(token, -4, 4) "#{first}...#{last}" end @doc """ Validates token format. npm tokens are typically UUIDs or base64-encoded strings. """ @spec valid_format?(String.t()) :: boolean() def valid_format?(token) do byte_size(token) >= 8 and not String.contains?(token, " ") and not String.contains?(token, "\n") end @doc """ Returns the auth header value for the given token. """ @spec auth_header(String.t()) :: String.t() def auth_header(token), do: "Bearer #{token}" @doc """ Reads token from an .npmrc file content. """ @spec parse_npmrc(String.t()) :: String.t() | nil def parse_npmrc(content) do content |> String.split("\n") |> Enum.find_value(fn line -> case Regex.run(~r/_authToken=(.+)$/, String.trim(line)) do [_, token] -> String.trim(token) _ -> nil end end) end defp read_from_npmrc do npmrc_path = Path.join(System.user_home!(), ".npmrc") case File.read(npmrc_path) do {:ok, content} -> parse_npmrc(content) _ -> nil end end end