Replace Geolix with Locus (#2362)

This PR replaces geolix with locus to simplify self-hosted setup. locus can auto-update maxmind dbs which are recommended for self-hosters if they want city-level geolocation. locus is also a bit faster.

This PR also uses a test mmdb file from https://github.com/maxmind/MaxMind-DB for e2e geolocation tests without stubs.
This commit is contained in:
ruslandoga 2023-01-17 22:05:09 +07:00 committed by GitHub
parent 2a4061de8c
commit 166748dcf2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 287 additions and 106 deletions

1
.gitignore vendored
View File

@ -63,6 +63,7 @@ plausible-report.xml
# Geolocation databases
/priv/geodb/*.mmdb
/priv/geodb/*.mmdb.gz
# Auto-generated tracker files
/priv/tracker/js/*.js

View File

@ -11,3 +11,4 @@ SELFHOST=false
SITE_LIMIT=3
HCAPTCHA_SITEKEY=test
HCAPTCHA_SECRET=scottiger
IP_GEOLOCATION_DB=test/priv/GeoLite2-City-Test.mmdb

View File

@ -142,11 +142,13 @@ geolite2_country_db =
get_var_from_path_or_env(
config_dir,
"GEOLITE2_COUNTRY_DB",
Application.app_dir(:plausible, "/priv/geodb/dbip-country.mmdb")
Application.app_dir(:plausible, "/priv/geodb/dbip-country.mmdb.gz")
)
ip_geolocation_db = get_var_from_path_or_env(config_dir, "IP_GEOLOCATION_DB", geolite2_country_db)
geonames_source_file = get_var_from_path_or_env(config_dir, "GEONAMES_SOURCE_FILE")
maxmind_license_key = get_var_from_path_or_env(config_dir, "MAXMIND_LICENSE_KEY")
maxmind_edition = get_var_from_path_or_env(config_dir, "MAXMIND_EDITION", "GeoLite2-City")
if System.get_env("DISABLE_AUTH") do
require Logger
@ -433,17 +435,38 @@ config :kaffy,
]
]
if config_env() != :test do
config :geolix,
databases: [
%{
id: :geolocation,
adapter: Geolix.Adapter.MMDB2,
source: ip_geolocation_db,
result_as: :raw
}
]
end
geo_opts =
cond do
maxmind_license_key ->
[
license_key: maxmind_license_key,
edition: maxmind_edition,
async: true
]
ip_geolocation_db ->
[path: ip_geolocation_db]
true ->
raise """
Missing geolocation database configuration.
Please set the IP_GEOLOCATION_DB environment value to the location of
your IP geolocation .mmdb file:
IP_GEOLOCATION_DB=/etc/plausible/dbip-city.mmdb
Or authenticate with MaxMind by
configuring MAXMIND_LICENSE_KEY and (optionally) MAXMIND_EDITION environment
variables:
MAXMIND_LICENSE_KEY=LNpsJCCKPis6XvBP
MAXMIND_EDITION=GeoLite2-City # this is the default edition
"""
end
config :plausible, Plausible.Geo, geo_opts
if geonames_source_file do
config :location, :geonames_source_file, geonames_source_file

View File

@ -24,45 +24,6 @@ config :plausible, :google,
config :bamboo, :refute_timeout, 10
geolix_sample_lookup = %{
city: %{geoname_id: 2_988_507, names: %{en: "Paris"}},
continent: %{code: "EU", geoname_id: 6_255_148, names: %{en: "Europe"}},
country: %{
geoname_id: 3_017_382,
is_in_european_union: true,
iso_code: "FR",
names: %{en: "France"}
},
ip_address: {2, 2, 2, 2},
location: %{
latitude: 48.8566,
longitude: 2.35222,
time_zone: "Europe/Paris",
weather_code: "FRXX0076"
},
postal: %{code: "75000"},
subdivisions: [
%{geoname_id: 3_012_874, iso_code: "IDF", names: %{en: "Île-de-France"}},
%{geoname_id: 2_968_815, iso_code: "75", names: %{en: "Paris"}}
]
}
config :geolix,
databases: [
%{
id: :geolocation,
adapter: Geolix.Adapter.Fake,
data: %{
{1, 1, 1, 1} => %{country: %{iso_code: "US"}},
{2, 2, 2, 2} => geolix_sample_lookup,
{1, 1, 1, 1, 1, 1, 1, 1} => %{country: %{iso_code: "US"}},
{0, 0, 0, 0} => %{country: %{iso_code: "ZZ"}, city: %{geoname_id: 123_123}},
{0, 0, 0, 1} => %{country: %{iso_code: "XX"}, subdivisions: [%{iso_code: "IDF"}]},
{0, 0, 0, 2} => %{country: %{iso_code: "T1"}, subdivisions: [%{}, %{iso_code: "IDF"}]}
}
}
]
config :plausible,
session_timeout: 0,
http_impl: Plausible.HTTPClient.Mock,

View File

@ -34,7 +34,7 @@ defmodule Mix.Tasks.DownloadCountryDatabase do
if res.status_code == 200 do
File.mkdir("priv/geodb")
File.write!("priv/geodb/dbip-country.mmdb", res.body)
File.write!("priv/geodb/dbip-country.mmdb.gz", res.body)
Logger.info("Downloaded and saved the database successfully")
else
Logger.error("Unable to download and save the database. Response: #{inspect(res)}")

View File

@ -30,9 +30,14 @@ defmodule Plausible.Application do
]
opts = [strategy: :one_for_one, name: Plausible.Supervisor]
setup_sentry()
setup_opentelemetry()
setup_geolocation()
Location.load_all()
Plausible.Geo.await_loader()
Supervisor.start_link(children, opts)
end
@ -119,4 +124,9 @@ defmodule Plausible.Application do
OpentelemetryEcto.setup([:plausible, :clickhouse_repo])
OpentelemetryOban.setup()
end
defp setup_geolocation do
opts = Application.fetch_env!(:plausible, Plausible.Geo)
:ok = Plausible.Geo.load_db(opts)
end
end

189
lib/plausible/geo.ex Normal file
View File

@ -0,0 +1,189 @@
defmodule Plausible.Geo do
@moduledoc """
This module provides an API for fetching IP geolocation.
"""
require Logger
@db :geolocation
@doc """
Starts the geodatabase loading process. Two modes are supported: local file
and MaxMind license key.
## Options
* `:path` - the path to the .mmdb database local file. When present,
`:license_key` and `:edition` are not required.
* `:license_key` - the [license key](https://support.maxmind.com/hc/en-us/articles/4407111582235-Generate-a-License-Key)
from MaxMind to authenticate requests to MaxMind.
* `:edition` - the name of the MaxMind database to be downloaded from MaxMind
servers. Defaults to `GeoLite2-City`.
* `:async` - when used, configures the database loading to run
asynchronously.
## Examples
Loading from a local file:
iex> load_db(path: "/etc/plausible/dbip-city.mmdb")
:ok
Downloading a MaxMind DB (this license key is no longer active):
iex> load_db(license_key: "LNpsJCCKPis6XvBP", edition: "GeoLite2-City", async: true)
:ok
"""
def load_db(opts) do
cond do
license_key = opts[:license_key] ->
edition = opts[:edition] || "GeoLite2-City"
:ok = :locus.start_loader(@db, {:maxmind, edition}, license_key: license_key)
path = opts[:path] ->
:ok = :locus.start_loader(@db, path)
true ->
raise "failed to load geolocation db: need :path or :license_key to be provided"
end
unless opts[:async] do
{:ok, _version} = :locus.await_loader(@db)
end
:ok
end
@doc """
Waits for the database to start after calling `load_db/1` with the async option.
"""
def await_loader, do: :locus.await_loader(@db)
@doc """
Returns geodatabase type.
Used for deciding whether to show the DB-IP disclaimer or not.
## Examples
In the case of a DB-IP database:
iex> database_type()
"DBIP-City-Lite"
In the case of a MaxMind database:
iex> database_type()
"GeoLite2-City"
"""
def database_type do
case :locus.get_info(@db, :metadata) do
{:ok, %{database_type: type}} -> type
_other -> nil
end
end
@doc """
Looks up geo info about an IP address.
## Examples
iex> lookup("8.7.6.5")
%{
"city" => %{
"geoname_id" => 5349755,
"names" => %{
"de" => "Fontana",
"en" => "Fontana",
"ja" => "フォンタナ",
"ru" => "Фонтана"
}
},
"continent" => %{
"code" => "NA",
"geoname_id" => 6255149,
"names" => %{
"de" => "Nordamerika",
"en" => "North America",
"es" => "Norteamérica",
"fr" => "Amérique du Nord",
"ja" => "北アメリカ",
"pt-BR" => "América do Norte",
"ru" => "Северная Америка",
"zh-CN" => "北美洲"
}
},
"country" => %{
"geoname_id" => 6252001,
"iso_code" => "US",
"names" => %{
"de" => "Vereinigte Staaten",
"en" => "United States",
"es" => "Estados Unidos",
"fr" => "États Unis",
"ja" => "アメリカ",
"pt-BR" => "EUA",
"ru" => "США",
"zh-CN" => "美国"
}
},
"location" => %{
"accuracy_radius" => 50,
"latitude" => 34.1211,
"longitude" => -117.4362,
"metro_code" => 803,
"time_zone" => "America/Los_Angeles"
},
"postal" => %{"code" => "92336"},
"registered_country" => %{
"geoname_id" => 6252001,
"iso_code" => "US",
"names" => %{
"de" => "Vereinigte Staaten",
"en" => "United States",
"es" => "Estados Unidos",
"fr" => "États Unis",
"ja" => "アメリカ",
"pt-BR" => "EUA",
"ru" => "США",
"zh-CN" => "美国"
}
},
"subdivisions" => [
%{
"geoname_id" => 5332921,
"iso_code" => "CA",
"names" => %{
"de" => "Kalifornien",
"en" => "California",
"es" => "California",
"fr" => "Californie",
"ja" => "カリフォルニア州",
"pt-BR" => "Califórnia",
"ru" => "Калифорния",
"zh-CN" => "加州"
}
}
]
}
"""
def lookup(ip_address) do
case :locus.lookup(@db, ip_address) do
{:ok, entry} ->
entry
:not_found ->
nil
{:error, reason} ->
Logger.error("failed to lookup ip address: " <> inspect(reason))
nil
end
end
end

View File

@ -168,7 +168,7 @@ defmodule Plausible.Ingestion.Event do
end
defp put_geolocation(%__MODULE__{} = event) do
result = Plausible.Ingestion.Geolocation.lookup(event.request.remote_ip)
result = Plausible.Ingestion.Geolocation.lookup(event.request.remote_ip) || %{}
update_attrs(event, result)
end

View File

@ -1,33 +1,39 @@
defmodule Plausible.Ingestion.Geolocation do
@moduledoc false
alias Plausible.Ingestion.CityOverrides
def lookup(remote_ip) do
result = Geolix.lookup(remote_ip, where: :geolocation)
def lookup(ip_address) do
case Plausible.Geo.lookup(ip_address) do
%{} = entry ->
country_code =
entry
|> get_in(["country", "iso_code"])
|> ignore_unknown_country()
country_code =
get_in(result, [:country, :iso_code])
|> ignore_unknown_country()
city_geoname_id = country_code && get_in(entry, ["city", "geoname_id"])
city_geoname_id = Plausible.Ingestion.CityOverrides.get(city_geoname_id, city_geoname_id)
city_geoname_id = country_code && get_in(result, [:city, :geoname_id])
city_geoname_id = CityOverrides.get(city_geoname_id, city_geoname_id)
%{
country_code: country_code,
subdivision1_code: subdivision1_code(country_code, entry),
subdivision2_code: subdivision2_code(country_code, entry),
city_geoname_id: city_geoname_id
}
%{
country_code: country_code,
subdivision1_code: subdivision1_code(country_code, result),
subdivision2_code: subdivision2_code(country_code, result),
city_geoname_id: city_geoname_id
}
nil ->
nil
end
end
defp subdivision1_code(country_code, %{subdivisions: [%{iso_code: iso_code} | _rest]})
defp subdivision1_code(country_code, %{"subdivisions" => [%{"iso_code" => iso_code} | _rest]})
when not is_nil(country_code) do
country_code <> "-" <> iso_code
end
defp subdivision1_code(_, _), do: nil
defp subdivision2_code(country_code, %{subdivisions: [_first, %{iso_code: iso_code} | _rest]})
defp subdivision2_code(country_code, %{
"subdivisions" => [_first, %{"iso_code" => iso_code} | _rest]
})
when not is_nil(country_code) do
country_code <> "-" <> iso_code
end

View File

@ -86,14 +86,7 @@ defmodule PlausibleWeb.Api.ExternalController do
|> Keyword.take([:version, :commit, :created, :tags])
|> Map.new()
geo_database =
case Geolix.metadata(where: :geolocation) do
%{database_type: type} ->
type
_ ->
"(not configured)"
end
geo_database = Plausible.Geo.database_type() || "(not configured)"
json(conn, %{
geo_database: geo_database,

View File

@ -316,14 +316,13 @@ defmodule PlausibleWeb.StatsController do
end
defp is_dbip() do
if Application.get_env(:plausible, :is_selfhost) do
case Geolix.metadata(where: :geolocation) do
%{database_type: type} ->
is_or_nil =
if Application.get_env(:plausible, :is_selfhost) do
if type = Plausible.Geo.database_type() do
String.starts_with?(type, "DBIP")
_ ->
false
end
end
end
!!is_or_nil
end
end

View File

@ -80,9 +80,8 @@ defmodule Plausible.MixProject do
{:floki, "~> 0.32.0", only: :test},
{:fun_with_flags, "~> 1.9.0"},
{:fun_with_flags_ui, "~> 0.8"},
{:locus, "~> 2.3"},
{:gen_cycle, "~> 1.0"},
{:geolix, "~> 2.0"},
{:geolix_adapter_mmdb2, "~> 0.6.0"},
{:hackney, "~> 1.8"},
{:hammer, "~> 6.0"},
{:httpoison, "~> 1.4"},

View File

@ -49,8 +49,6 @@
"fun_with_flags_ui": {:hex, :fun_with_flags_ui, "0.8.0", "70587e344ba2035516a639e7bd8cb2ce8d54ee6c5f5dfd3e4e6f6a776e14ac1d", [:mix], [{:cowboy, ">= 2.0.0", [hex: :cowboy, repo: "hexpm", optional: true]}, {:fun_with_flags, "~> 1.8", [hex: :fun_with_flags, repo: "hexpm", optional: false]}, {:plug, "~> 1.12", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 2.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm", "95e1e5afae77e259a4a43f930f3da97ff3c388a72d4622f7848cb7ee34de6338"},
"gen_cycle": {:hex, :gen_cycle, "1.0.3", "ee0117b9c65814f58827abfe84967d4cb5380db0fbac992358e5b669b3ebcbcb", [:rebar3], [], "hexpm", "fffdadf7fb73de75e3429eb8a6982768e7240803561942602350b689991749e4"},
"gen_smtp": {:hex, :gen_smtp, "1.2.0", "9cfc75c72a8821588b9b9fe947ae5ab2aed95a052b81237e0928633a13276fd3", [:rebar3], [{:ranch, ">= 1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "5ee0375680bca8f20c4d85f58c2894441443a743355430ff33a783fe03296779"},
"geolix": {:hex, :geolix, "2.0.0", "7e65764bedfc98d08a3ddb24c417657c9d438eff163280b45fbb7de289626acd", [:mix], [], "hexpm", "8742bf588ed0bb7def2c443204d09d355990846c6efdff96ded66aac24c301df"},
"geolix_adapter_mmdb2": {:hex, :geolix_adapter_mmdb2, "0.6.0", "6ab9dbf6ea395817aa1fd2597be25d0dda1853c7f664e62716e47728d18bc4f9", [:mix], [{:geolix, "~> 2.0", [hex: :geolix, repo: "hexpm", optional: false]}, {:mmdb2_decoder, "~> 3.0", [hex: :mmdb2_decoder, repo: "hexpm", optional: false]}], "hexpm", "06ff962feae8a310cffdf86b74bfcda6e2d0dccb439bb1f62df2b657b1c0269b"},
"gettext": {:hex, :gettext, "0.19.1", "564953fd21f29358e68b91634799d9d26989f8d039d7512622efb3c3b1c97892", [:mix], [], "hexpm", "10c656c0912b8299adba9b061c06947511e3f109ab0d18b44a866a4498e77222"},
"gproc": {:hex, :gproc, "0.8.0", "cea02c578589c61e5341fce149ea36ccef236cc2ecac8691fba408e7ea77ec2f", [:rebar3], [], "hexpm", "580adafa56463b75263ef5a5df4c86af321f68694e7786cb057fd805d1e2a7de"},
"grpcbox": {:hex, :grpcbox, "0.16.0", "b83f37c62d6eeca347b77f9b1ec7e9f62231690cdfeb3a31be07cd4002ba9c82", [:rebar3], [{:acceptor_pool, "~>1.0.0", [hex: :acceptor_pool, repo: "hexpm", optional: false]}, {:chatterbox, "~>0.13.0", [hex: :ts_chatterbox, repo: "hexpm", optional: false]}, {:ctx, "~>0.6.0", [hex: :ctx, repo: "hexpm", optional: false]}, {:gproc, "~>0.8.0", [hex: :gproc, repo: "hexpm", optional: false]}], "hexpm", "294df743ae20a7e030889f00644001370a4f7ce0121f3bbdaf13cf3169c62913"},
@ -67,6 +65,7 @@
"jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},
"kaffy": {:hex, :kaffy, "0.9.0", "bef34c9729f6a3af4d0dea8eede8bcb9e11371a83ac9a8b393991bce81839517", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.11", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm", "d18ff57b8e68feb433aed11e71510cd357abc7034e75358af5deff7d0d4c6ed3"},
"location": {:git, "https://github.com/plausible/location.git", "8faf4f08b06905adde43554dc1d9d35675654816", []},
"locus": {:hex, :locus, "2.3.6", "c9f53fd5df872fca66a54dc0aa2f8b2d3640388e56a0c39a741be0df6d8854bf", [:rebar3], [{:tls_certificate_check, "~> 1.9", [hex: :tls_certificate_check, repo: "hexpm", optional: false]}], "hexpm", "6087aa9a69673e7011837fb4b3d7f756560adde76892c32f5f93904ee30064e2"},
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
@ -75,7 +74,6 @@
"mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"mint": {:hex, :mint, "1.4.2", "50330223429a6e1260b2ca5415f69b0ab086141bc76dc2fbf34d7c389a6675b2", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "ce75a5bbcc59b4d7d8d70f8b2fc284b1751ffb35c7b6a6302b5192f8ab4ddd80"},
"mmdb2_decoder": {:hex, :mmdb2_decoder, "3.0.1", "78e3aedde88035c6873ada5ceaf41b7f15a6259ed034e0eaca72ccfa937798f0", [:mix], [], "hexpm", "316af0f388fac824782d944f54efe78e7c9691bbbdb0afd5cccdd0510adf559d"},
"mox": {:hex, :mox, "1.0.2", "dc2057289ac478b35760ba74165b4b3f402f68803dd5aecd3bfd19c183815d64", [:mix], [], "hexpm", "f9864921b3aaf763c8741b5b8e6f908f44566f1e427b2630e89e9a73b981fef2"},
"nanoid": {:hex, :nanoid, "2.0.5", "1d2948d8967ef2d948a58c3fef02385040bd9823fc6394bd604b8d98e5516b22", [:mix], [], "hexpm", "956e8876321104da72aa48770539ff26b36b744cd26753ec8e7a8a37e53d5f58"},
"nimble_options": {:hex, :nimble_options, "0.5.1", "5c166f7669e40333191bea38e3bd3811cc13f459f1e4be49e89128a21b5d8c4d", [:mix], [], "hexpm", "d176cf7baa4fef0ceb301ca3eb8b55bd7de3e45f489c4f8b4f2849f1f114ef3e"},

View File

@ -651,7 +651,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
assert event.referrer == ""
end
# Fake data is set up in config/test.exs
# Fake geo is loaded from test/priv/GeoLite2-City-Test.mmdb
test "looks up location data from the ip address", %{conn: conn, domain: domain} do
params = %{
name: "pageview",
@ -660,15 +660,15 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
}
conn
|> put_req_header("x-forwarded-for", "2.2.2.2")
|> put_req_header("x-forwarded-for", "2.125.160.216")
|> post("/api/event", params)
pageview = get_event(domain)
assert pageview.country_code == "FR"
assert pageview.subdivision1_code == "FR-IDF"
assert pageview.subdivision2_code == "FR-75"
assert pageview.city_geoname_id == 2_988_507
assert pageview.country_code == "GB"
assert pageview.subdivision1_code == "GB-ENG"
assert pageview.subdivision2_code == "GB-WBK"
assert pageview.city_geoname_id == 2_655_045
end
test "ignores unknown country code ZZ", %{conn: conn, domain: domain} do
@ -736,7 +736,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
}
conn
|> put_req_header("x-forwarded-for", "1.1.1.1:123")
|> put_req_header("x-forwarded-for", "216.160.83.56:123")
|> post("/api/event", params)
pageview = get_event(domain)
@ -752,12 +752,12 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
}
conn
|> put_req_header("x-forwarded-for", "1:1:1:1:1:1:1:1")
|> put_req_header("x-forwarded-for", "2001:218:1:1:1:1:1:1")
|> post("/api/event", params)
pageview = get_event(domain)
assert pageview.country_code == "US"
assert pageview.country_code == "JP"
end
test "works with ipv6 with a port number in x-forwarded-for", %{conn: conn, domain: domain} do
@ -768,12 +768,12 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
}
conn
|> put_req_header("x-forwarded-for", "[1:1:1:1:1:1:1:1]:123")
|> put_req_header("x-forwarded-for", "[2001:218:1:1:1:1:1:1]:123")
|> post("/api/event", params)
pageview = get_event(domain)
assert pageview.country_code == "US"
assert pageview.country_code == "JP"
end
test "uses cloudflare's special header for client IP address if present", %{
@ -788,7 +788,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
conn
|> put_req_header("x-forwarded-for", "0.0.0.0")
|> put_req_header("cf-connecting-ip", "1.1.1.1")
|> put_req_header("cf-connecting-ip", "216.160.83.56")
|> post("/api/event", params)
pageview = get_event(domain)
@ -808,7 +808,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
conn
|> put_req_header("x-forwarded-for", "0.0.0.0")
|> put_req_header("b-forwarded-for", "1.1.1.1,9.9.9.9")
|> put_req_header("b-forwarded-for", "216.160.83.56,9.9.9.9")
|> post("/api/event", params)
pageview = get_event(domain)
@ -827,7 +827,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
}
conn
|> put_req_header("forwarded", "by=0.0.0.0;for=1.1.1.1;host=somehost.com;proto=https")
|> put_req_header("forwarded", "by=0.0.0.0;for=216.160.83.56;host=somehost.com;proto=https")
|> post("/api/event", params)
pageview = get_event(domain)
@ -845,13 +845,13 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
conn
|> put_req_header(
"forwarded",
"by=0.0.0.0;for=\"[1:1:1:1:1:1:1:1]\",for=0.0.0.0;host=somehost.com;proto=https"
"by=0.0.0.0;for=\"[2001:218:1:1:1:1:1:1]\",for=0.0.0.0;host=somehost.com;proto=https"
)
|> post("/api/event", params)
pageview = get_event(domain)
assert pageview.country_code == "US"
assert pageview.country_code == "JP"
end
test "URL is decoded", %{conn: conn, domain: domain} do
@ -1042,7 +1042,7 @@ defmodule PlausibleWeb.Api.ExternalControllerTest do
conn
|> put_req_header("user-agent", @user_agent)
|> put_req_header("x-forwarded-for", "982.32.12.1")
|> put_req_header("x-forwarded-for", "82.32.12.1")
|> post("/api/event", params)
[one, two] = get_events(domain)

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

1
test/priv/README.md Normal file
View File

@ -0,0 +1 @@
`GeoLite2-City-Test.mmdb` is downloaded from https://github.com/maxmind/MaxMind-DB