mirror of
https://github.com/plausible/analytics.git
synced 2024-08-17 05:40:24 +03:00
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:
parent
2a4061de8c
commit
166748dcf2
1
.gitignore
vendored
1
.gitignore
vendored
@ -63,6 +63,7 @@ plausible-report.xml
|
||||
|
||||
# Geolocation databases
|
||||
/priv/geodb/*.mmdb
|
||||
/priv/geodb/*.mmdb.gz
|
||||
|
||||
# Auto-generated tracker files
|
||||
/priv/tracker/js/*.js
|
||||
|
@ -11,3 +11,4 @@ SELFHOST=false
|
||||
SITE_LIMIT=3
|
||||
HCAPTCHA_SITEKEY=test
|
||||
HCAPTCHA_SECRET=scottiger
|
||||
IP_GEOLOCATION_DB=test/priv/GeoLite2-City-Test.mmdb
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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)}")
|
||||
|
@ -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
189
lib/plausible/geo.ex
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
3
mix.exs
3
mix.exs
@ -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"},
|
||||
|
4
mix.lock
4
mix.lock
@ -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"},
|
||||
|
@ -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)
|
||||
|
BIN
test/priv/GeoLite2-City-Test.mmdb
Normal file
BIN
test/priv/GeoLite2-City-Test.mmdb
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
1
test/priv/README.md
Normal file
1
test/priv/README.md
Normal file
@ -0,0 +1 @@
|
||||
`GeoLite2-City-Test.mmdb` is downloaded from https://github.com/maxmind/MaxMind-DB
|
Loading…
Reference in New Issue
Block a user