factorio: download using token, not password

Downloads were broken by upstream devs' addition of CAPTCHA to the login
form. We now need only a slightly modified fetchurl to retrieve the
binary distribution.
This commit is contained in:
Eric Litak 2018-09-11 17:49:42 -07:00
parent 047c23782c
commit ff22306255
3 changed files with 73 additions and 119 deletions

View File

@ -3,7 +3,7 @@
, factorio-utils
, releaseType
, mods ? []
, username ? "" , password ? ""
, username ? "", token ? "" # get/reset token at https://factorio.com/profile
, experimental ? false
}:
@ -13,59 +13,101 @@ assert releaseType == "alpha"
let
# NB If you nix-prefetch-url any of these, be sure to add a --name arg,
# where the ultimate "_" (before the version) is changed to a "-".
helpMsg = ''
===FETCH FAILED===
Please ensure you have set the username and token with config.nix, or
/etc/nix/nixpkgs-config.nix if on NixOS.
Your token can be seen at https://factorio.com/profile (after logging in). It is
not as sensitive as your password, but should still be safeguarded. There is a
link on that page to revoke/invalidate the token, if you believe it has been
leaked or wish to take precautions.
Example:
{
packageOverrides = pkgs: {
factorio = pkgs.factorio.override {
username = "FactorioPlayer1654";
token = "d5ad5a8971267c895c0da598688761";
};
};
}
Alternatively, instead of providing the username+token, you may manually
download the release through https://factorio.com/download , then add it to
the store using e.g.:
releaseType=alpha
version=0.16.51
nix-prefetch-url file://$HOME/Downloads/factorio_\''${releaseType}_x64_\''${version}.tar.xz --name factorio_\''${releaseType}_x64-\''${version}.tar.xz
Note the ultimate "_" is replaced with "-" in the --name arg!
'';
branch = if experimental then "experimental" else "stable";
binDists = {
x86_64-linux = let bdist = bdistForArch { inUrl = "linux64"; inTar = "x64"; }; in {
alpha = {
stable = bdist { sha256 = "0b4hbpdcrh5hgip9q5dkmw22p66lcdhnr0kmb0w5dw6yi7fnxxh0"; fetcher = authenticatedFetch; };
experimental = bdist { sha256 = "1qwfivl5wf0ii8c4prdl4yili23qimsh2cj874r37q3ygpjk3bd3"; version = "0.16.50"; fetcher = authenticatedFetch; };
stable = bdist { sha256 = "0b4hbpdcrh5hgip9q5dkmw22p66lcdhnr0kmb0w5dw6yi7fnxxh0"; version = "0.16.51"; withAuth = true; };
experimental = bdist { sha256 = "1qwfivl5wf0ii8c4prdl4yili23qimsh2cj874r37q3ygpjk3bd3"; version = "0.16.50"; withAuth = true; };
};
headless = {
stable = bdist { sha256 = "0zrnpg2js0ysvx9y50h3gajldk16mv02dvrwnkazh5kzr1d9zc3c"; };
stable = bdist { sha256 = "0zrnpg2js0ysvx9y50h3gajldk16mv02dvrwnkazh5kzr1d9zc3c"; version = "0.16.51"; };
experimental = bdist { sha256 = "00691kr85p58qpxf3889p20nrgsvsyspx3c8yd11dkg46wly06z1"; version = "0.16.50"; };
};
demo = {
stable = bdist { sha256 = "0zf61z8937yd8pyrjrqdjgd0rjl7snwrm3xw86vv7s7p835san6a"; version = "0.16.51"; };
experimental = bdist { };
};
};
i686-linux = let bdist = bdistForArch { inUrl = "linux32"; inTar = "i386"; }; in {
alpha = {
stable = bdist { sha256 = "0nnfkxxqnywx1z05xnndgh71gp4izmwdk026nnjih74m2k5j086l"; version = "0.14.23"; nameMut = asGz; };
experimental = bdist { };
};
headless = {
stable = bdist { };
experimental = bdist { };
};
demo = {
stable = bdist { };
experimental = bdist { };
stable = bdist { sha256 = "0nnfkxxqnywx1z05xnndgh71gp4izmwdk026nnjih74m2k5j086l"; version = "0.14.23"; withAuth = true; nameMut = asGz; };
};
};
};
actual = binDists.${stdenv.hostPlatform.system}.${releaseType}.${branch} or (throw "Factorio: unsupported platform");
bdistForArch = arch: { sha256 ? null
, version ? "0.16.51"
, fetcher ? fetchurl
actual = binDists.${stdenv.hostPlatform.system}.${releaseType}.${branch} or (throw "Factorio ${releaseType}-${branch} binaries for ${stdenv.hostPlatform.system} are not available for download.");
bdistForArch = arch: { version
, sha256
, withAuth ? false
, nameMut ? x: x
}:
if sha256 == null then
throw "Factorio ${releaseType}-${arch.inTar} binaries are not (and were never?) available to download"
else {
let
url = "https://factorio.com/get-download/${version}/${releaseType}/${arch.inUrl}";
name = nameMut "factorio_${releaseType}_${arch.inTar}-${version}.tar.xz";
in {
inherit version arch;
src = fetcher {
inherit sha256;
url = "https://www.factorio.com/get-download/${version}/${releaseType}/${arch.inUrl}";
name = nameMut "factorio_${releaseType}_${arch.inTar}-${version}.tar.xz";
};
src =
if withAuth then
(stdenv.lib.overrideDerivation
(fetchurl {
inherit name url sha256;
curlOpts = [
"--get"
"--data-urlencode" "username@username"
"--data-urlencode" "token@token"
];
})
(_: { # This preHook hides the credentials from /proc
preHook = ''
echo -n "${username}" >username
echo -n "${token}" >token
'';
failureHook = ''
cat <<EOF
${helpMsg}
EOF
'';
})
)
else
fetchurl { inherit name url sha256; };
};
authenticatedFetch = callPackage ./fetch.nix { inherit username password; };
asGz = builtins.replaceStrings [".xz"] [".gz"];
asGz = builtins.replaceStrings [".xz"] [".gz"];
configBaseCfg = ''
use-system-read-write-data-directories=false

View File

@ -1,33 +0,0 @@
{ stdenv, curl, xidel, cacert
# Begin download parameters
, username ? ""
, password ? ""
}:
{
# URL to fetch.
url ? ""
, name ? "factorio.tar.gz"
# Login URL.
, loginUrl ? "https://www.factorio.com/login"
# SHA256 of the fetched URL.
, sha256 ? ""
}:
stdenv.mkDerivation {
nativeBuildInputs = [ curl xidel ];
inherit name url loginUrl username password cacert;
builder = ./fetch.sh;
outputHashAlgo = "sha256";
outputHash = sha256;
outputHashMode = "flat";
# There's no point in downloading remotely, we'd just slow things down.
preferLocalBuild = true;
}

View File

@ -1,55 +0,0 @@
source $stdenv/setup
# Curl flags to increase reliability a bit.
#
# Can't use fetchurl, for several reasons. One is that we definitely
# don't want --insecure for the login, though we need it for the
# download as their download cert isn't in the standard linux bundle.
curl="curl \
--max-redirs 20 \
--retry 3 \
--cacert $cacert/etc/ssl/certs/ca-bundle.crt \
-b cookies \
-c cookies \
$curlOpts \
$NIX_CURL_FLAGS"
# We don't want the password to be on any program's argv, as it may be
# visible in /proc. Writing it to file with echo should be safe, since
# it's a shell builtin.
echo -n "$password" > password
# Might as well hide the username as well.
echo -n "$username" > username
# Get a CSRF token.
csrf=$($curl $loginUrl | xidel - -e '//input[@id="csrf_token"]/@value')
# Log in. We don't especially care about the result, but let's check if login failed.
$curl --data-urlencode csrf_token="$csrf" \
--data-urlencode username_or_email@username \
--data-urlencode password@password \
-d action=Login \
$loginUrl -D headers > /dev/null
if grep -q 'Location: https://' headers; then
# Now download. We need --insecure for this, but the sha256 should cover us.
$curl --insecure --location --fail $url > $out || { echo "Login succeeded, but subsequent fetch failed."; exit 1; }
set +x
else
set +x
echo 'Login failed'
echo 'Please set username and password with config.nix,'
echo 'or /etc/nix/nixpkgs-config.nix if on NixOS.'
echo
echo 'Example:'
echo '{'
echo ' packageOverrides = pkgs: rec {'
echo ' factorio = pkgs.factorio.override {'
echo ' username = "<username or email address>";'
echo ' password = "<password>";'
echo ' };'
echo ' };'
echo '}'
exit 1
fi