aboutsummaryrefslogtreecommitdiff
path: root/m4/guix.m4
blob: 721285b01498e8ebae9c1e1a28d0e0784c066b4f (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
dnl GNU Guix --- Functional package management for GNU
dnl Copyright © 2012, 2013, 2014, 2015, 2016, 2018 Ludovic Courtès <ludo@gnu.org>
dnl Copyright © 2014 Mark H Weaver <mhw@netris.org>
dnl Copyright © 2017 Efraim Flashner <efraim@flashner.co.il>
dnl
dnl This file is part of GNU Guix.
dnl
dnl GNU Guix is free software; you can redistribute it and/or modify it
dnl under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 3 of the License, or (at
dnl your option) any later version.
dnl
dnl GNU Guix is distributed in the hope that it will be useful, but
dnl WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
dnl GNU General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.

dnl GUIX_ASSERT_LIBGCRYPT_USABLE
dnl
dnl Assert that GNU libgcrypt is usable from Guile.
AC_DEFUN([GUIX_ASSERT_LIBGCRYPT_USABLE],
  [AC_CACHE_CHECK([whether $LIBGCRYPT can be dynamically loaded],
    [guix_cv_libgcrypt_usable_p],
    [GUILE_CHECK([retval],
      [(dynamic-func \"gcry_md_hash_buffer\" (dynamic-link \"$LIBGCRYPT\"))])
     if test "$retval" = 0; then
       guix_cv_libgcrypt_usable_p="yes"
     else
       guix_cv_libgcrypt_usable_p="no"
     fi])

   if test "x$guix_cv_libgcrypt_usable_p" != "xyes"; then
     AC_MSG_ERROR([GNU libgcrypt does not appear to be usable; see `--with-libgcrypt-prefix' and `README'.])
   fi])

dnl GUIX_SYSTEM_TYPE
dnl
dnl Determine the Guix host system type, and store it in the
dnl `guix_system' variable.
AC_DEFUN([GUIX_SYSTEM_TYPE], [
  AC_REQUIRE([AC_CANONICAL_HOST])
  AC_PATH_PROG([SED], [sed])

  AC_ARG_WITH(system, AC_HELP_STRING([--with-system=SYSTEM],
    [Platform identifier (e.g., `i686-linux').]),
    [guix_system="$withval"],
    [case "$host_cpu" in
       i*86)
	  machine_name="i686";;
       amd64)
          machine_name="x86_64";;
       arm|armv[[7-9]]*)
          # Here we want to exclude CPUs such as "armv6l".  On ARMv7
          # machines, we normally get "armv7l".  However, in Guix, we
          # configure with --build=arm-unknown-linux-gnueabihf, leading
          # to just "arm", so we also have to allow it.
          #
          # TODO: If not cross-compiling, add a sanity check to make
          #       sure this build machine has the needed features to
          #       support executables compiled using our armhf gcc,
          #       configured with:
          #         --with-arch=armv7-a
          #         --with-float=hard
          #         --with-mode=thumb
          #         --with-fpu=vfpv3-d16
	  machine_name="armhf";;
       *)
	  machine_name="$host_cpu";;
     esac

     case "$host_os" in
       linux-gnu*)
	  # For backward compatibility, strip the `-gnu' part.
	  guix_system="$machine_name-linux";;
       gnu*)
          # Always use i586 for GNU/Hurd.
          guix_system="i586-gnu";;
       *)
	  # Strip the version number from names such as `gnu0.3',
	  # `darwin10.2.0', etc.
	  guix_system="$machine_name-`echo $host_os | "$SED" -e's/[0-9.]*$//g'`";;
     esac])

  AC_MSG_CHECKING([for the Guix system type])
  AC_MSG_RESULT([$guix_system])

  AC_SUBST([guix_system])
])

dnl GUIX_ASSERT_SUPPORTED_SYSTEM
dnl
dnl Assert that this is a system to which the distro is ported.
AC_DEFUN([GUIX_ASSERT_SUPPORTED_SYSTEM], [
  AC_REQUIRE([GUIX_SYSTEM_TYPE])

  AC_ARG_WITH([courage], [AC_HELP_STRING([--with-courage],
    [Assert that even if this platform is unsupported, you will be
courageous and port the GNU System distribution to it (see
"GNU Distribution" in the manual.)])],
    [guix_courageous="$withval"],
    [guix_courageous="no"])

  # Currently only Linux-based systems are supported, and only on some
  # platforms.
  case "$guix_system" in
    x86_64-linux|i686-linux|armhf-linux|aarch64-linux|mips64el-linux)
      ;;
    *)
      if test "x$guix_courageous" = "xyes"; then
        AC_MSG_WARN([building Guix on `$guix_system', which is not supported])
      else
        AC_MSG_ERROR([`$guix_system' is not a supported platform.
See "GNU Distribution" in the manual, or try `--with-courage'.])
      fi
      ;;
  esac
])

dnl GUIX_ASSERT_GUILE_FEATURES FEATURES
dnl
dnl Assert that FEATURES are provided by $GUILE.
AC_DEFUN([GUIX_ASSERT_GUILE_FEATURES], [
  for guix_guile_feature in $1
  do
    AC_MSG_CHECKING([whether $GUILE provides feature '$guix_guile_feature'])
    if "$GUILE" -c "(exit (provided? '$guix_guile_feature))"
    then
      AC_MSG_RESULT([yes])
    else
      AC_MSG_RESULT([no])
      AC_MSG_ERROR([$GUILE does not support feature '$guix_guile_feature', which is required.])
    fi
  done
])

dnl GUIX_CHECK_UNBUFFERED_CBIP
dnl
dnl Check whether 'setbvuf' works on custom binary input ports (CBIPs), as is
dnl the case starting with Guile 2.0.10.
AC_DEFUN([GUIX_CHECK_UNBUFFERED_CBIP], [
  AC_CACHE_CHECK([whether Guile's custom binary input ports support 'setvbuf'],
    [ac_cv_guix_cbips_support_setvbuf],
    [if "$GUILE" -c "(use-modules (rnrs io ports))			\
       (let ((p (make-custom-binary-input-port \"cbip\" pk #f #f #f)))	\
         (setvbuf p _IONBF))" >&5 2>&1
     then
       ac_cv_guix_cbips_support_setvbuf=yes
     else
       ac_cv_guix_cbips_support_setvbuf=no
     fi])
])

dnl GUIX_ASSERT_SYNTAX_OBJECT_EQUAL
dnl
dnl Guile 2.2.1 was a brown-paper-bag release where 'equal?' wouldn't work
dnl for syntax objects, which broke gexps.  Unfortunately Fedora 25 provides it.
dnl Reject it.
AC_DEFUN([GUIX_ASSERT_SYNTAX_OBJECT_EQUAL], [
  AC_CACHE_CHECK([whether 'equal?' works for syntax objects],
    [ac_cv_guix_syntax_object_equal],
    [if "$GUILE" -c '(exit (equal? (syntax x) (syntax x)))'
     then
       ac_cv_guix_syntax_object_equal=yes
     else
       ac_cv_guix_syntax_object_equal=no
     fi])
  if test "x$ac_cv_guix_syntax_object_equal" != xyes; then
    # This bug was present in Guile 2.2.1 only.
    AC_MSG_ERROR(['equal?' does not work for syntax object; upgrade to Guile 2.2.2 or later.])
  fi
])

dnl GUIX_CHECK_GUILE_SSH
dnl
dnl Check whether a recent-enough Guile-SSH is available.
AC_DEFUN([GUIX_CHECK_GUILE_SSH], [
  dnl Check whether 'channel-send-eof' (introduced in 0.10.2) is present.
  AC_CACHE_CHECK([whether Guile-SSH is available and recent enough],
    [guix_cv_have_recent_guile_ssh],
    [GUILE_CHECK([retval],
      [(and (@ (ssh channel) channel-send-eof)
            (@ (ssh popen) open-remote-pipe)
	    (@ (ssh dist node) node-eval))])
     if test "$retval" = 0; then
       guix_cv_have_recent_guile_ssh="yes"
     else
       guix_cv_have_recent_guile_ssh="no"
     fi])
])

dnl GUIX_TEST_ROOT_DIRECTORY
AC_DEFUN([GUIX_TEST_ROOT_DIRECTORY], [
  AC_CACHE_CHECK([for unit test root directory],
    [ac_cv_guix_test_root],
    [ac_cv_guix_test_root="`pwd`/test-tmp"])
])

dnl 'BINPRM_BUF_SIZE' constant in Linux (we leave room for the trailing zero.)
dnl The Hurd has a limit of about a page (see exec/hashexec.c.)
m4_define([LINUX_HASH_BANG_LIMIT], 127)

dnl Hardcoded 'sun_path' length in <sys/un.h>.
m4_define([SOCKET_FILE_NAME_LIMIT], 108)

dnl GUIX_SOCKET_FILE_NAME_LENGTH
AC_DEFUN([GUIX_SOCKET_FILE_NAME_LENGTH], [
  AC_CACHE_CHECK([the length of the installed socket file name],
    [ac_cv_guix_socket_file_name_length],
    [ac_cv_guix_socket_file_name_length="`echo -n "$guix_localstatedir/guix/daemon-socket/socket" | wc -c`"])
])

dnl GUIX_TEST_SOCKET_FILE_NAME_LENGTH
AC_DEFUN([GUIX_TEST_SOCKET_FILE_NAME_LENGTH], [
  AC_REQUIRE([GUIX_TEST_ROOT_DIRECTORY])
  AC_CACHE_CHECK([the length of the socket file name used in tests],
    [ac_cv_guix_test_socket_file_name_length],
    [ac_cv_guix_test_socket_file_name_length="`echo -n "$ac_cv_guix_test_root/var/123456/daemon-socket/socket" | wc -c`"])
])

dnl GUIX_HASH_BANG_LENGTH
AC_DEFUN([GUIX_HASH_BANG_LENGTH], [
  AC_CACHE_CHECK([the length of a typical hash bang line],
    [ac_cv_guix_hash_bang_length],
    [ac_cv_guix_hash_bang_length=`echo -n "$storedir/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bootstrap-binaries-0/bin/bash" | wc -c`])
])

dnl GUIX_TEST_HASH_BANG_LENGTH
AC_DEFUN([GUIX_TEST_HASH_BANG_LENGTH], [
  AC_REQUIRE([GUIX_TEST_ROOT_DIRECTORY])
  AC_CACHE_CHECK([the length of a hash bang line used in tests],
    [ac_cv_guix_test_hash_bang_length],
    [ac_cv_guix_test_hash_bang_length=`echo -n "$ac_cv_guix_test_root/store/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bootstrap-binaries-0/bin/bash" | wc -c`])
])

dnl GUIX_CHECK_FILE_NAME_LIMITS
dnl
dnl GNU/Linux has a couple of silly limits that we can easily run into.
dnl Make sure everything is fine with the current settings.  Set $1 to
dnl 'yes' if tests can run, 'no' otherwise.
AC_DEFUN([GUIX_CHECK_FILE_NAME_LIMITS], [
  AC_REQUIRE([GUIX_SOCKET_FILE_NAME_LENGTH])
  AC_REQUIRE([GUIX_TEST_SOCKET_FILE_NAME_LENGTH])
  AC_REQUIRE([GUIX_HASH_BANG_LENGTH])
  AC_REQUIRE([GUIX_TEST_HASH_BANG_LENGTH])

  if test "$ac_cv_guix_socket_file_name_length" -ge ]SOCKET_FILE_NAME_LIMIT[; then
    AC_MSG_ERROR([socket file name would exceed the maxium allowed length])
  fi
  if test "$ac_cv_guix_test_socket_file_name_length" -ge ]SOCKET_FILE_NAME_LIMIT[; then
    AC_MSG_WARN([socket file name limit may be exceeded when running tests])
  fi

  $1=yes
  if test "$ac_cv_guix_hash_bang_length" -ge ]LINUX_HASH_BANG_LIMIT[; then
    $1=no
    AC_MSG_ERROR([store directory '$storedir' would lead to overly long hash-bang lines])
  fi
  if test "$ac_cv_guix_test_hash_bang_length" -ge ]LINUX_HASH_BANG_LIMIT[; then
    $1=no
    AC_MSG_WARN([test directory '$ac_cv_guix_test_root' may lead to overly long hash-bang lines])
  fi
])

dnl GUIX_CHECK_CXX11
dnl
dnl Check whether the C++ compiler can compile a typical C++11 program.
AC_DEFUN([GUIX_CHECK_CXX11], [
  AC_REQUIRE([AC_PROG_CXX])
  AC_CACHE_CHECK([whether $CXX supports C++11],
    [ac_cv_guix_cxx11_support],
    [save_CXXFLAGS="$CXXFLAGS"
     CXXFLAGS="-std=c++11 $CXXFLAGS"
     AC_COMPILE_IFELSE([
      AC_LANG_SOURCE([
	#include <functional>

	std::function<int(int)>
	return_plus_lambda (int x)
	{
	  auto result = [[&]](int y) {
	    return x + y;
	  };

	  return result;
	}
      ])],
      [ac_cv_guix_cxx11_support=yes],
      [ac_cv_guix_cxx11_support=no])
    CXXFLAGS="$save_CXXFLAGS"
  ])
])

dnl GUIX_ASSERT_CXX11
dnl
dnl Error out if the C++ compiler cannot compile C++11 code.
AC_DEFUN([GUIX_ASSERT_CXX11], [
  GUIX_CHECK_CXX11
  if test "x$ac_cv_guix_cxx11_support" != "xyes"; then
    AC_MSG_ERROR([C++ compiler '$CXX' does not support the C++11 standard])
  fi
])

dnl GUIX_LIBGCRYPT_LIBDIR VAR
dnl
dnl Attempt to determine libgcrypt's LIBDIR; store the result in VAR.
AC_DEFUN([GUIX_LIBGCRYPT_LIBDIR], [
  AC_PATH_PROG([LIBGCRYPT_CONFIG], [libgcrypt-config])
  AC_CACHE_CHECK([libgcrypt's library directory],
    [guix_cv_libgcrypt_libdir],
    [if test "x$LIBGCRYPT_CONFIG" != "x"; then
       guix_cv_libgcrypt_libdir=`$LIBGCRYPT_CONFIG --libs | grep -e -L | sed -e "s/.*-L\([[^ ]]\+\)[[[:blank:]]]\+-lgcrypt.*/\1/g"`
     else
       guix_cv_libgcrypt_libdir=""
     fi])
  $1="$guix_cv_libgcrypt_libdir"
])

dnl GUIX_LIBZ_LIBDIR VAR
dnl
dnl Attempt to determine libz's LIBDIR; store the result in VAR.
AC_DEFUN([GUIX_LIBZ_LIBDIR], [
  AC_REQUIRE([PKG_PROG_PKG_CONFIG])
  AC_CACHE_CHECK([zlib's library directory],
    [guix_cv_libz_libdir],
    [guix_cv_libz_libdir="`$PKG_CONFIG zlib --variable=libdir 2> /dev/null`"])
  $1="$guix_cv_libz_libdir"
])

dnl GUIX_CURRENT_LOCALSTATEDIR
dnl
dnl Determine the localstatedir of an existing Guix installation and set
dnl 'guix_cv_current_localstatedir' accordingly.  Set it to "none" if no
dnl existing installation was found.
AC_DEFUN([GUIX_CURRENT_LOCALSTATEDIR], [
  AC_PATH_PROG([GUILE], [guile])
  AC_CACHE_CHECK([the current installation's localstatedir],
    [guix_cv_current_localstatedir],
    [dnl Call 'dirname' because (guix config) appends "/guix" to LOCALSTATEDIR.
     guix_cv_current_localstatedir="`"$GUILE" \
       -c '(use-modules (guix config))
           (when (string=? %store-directory "'$storedir'")
             (display (dirname %state-directory)))' \
       2>/dev/null`"
     if test "x$guix_cv_current_localstatedir" = "x"; then
       guix_cv_current_localstatedir=none
     fi])])

dnl GUIX_CHECK_LOCALSTATEDIR
dnl
dnl Check that the LOCALSTATEDIR value is consistent with that of the existing
dnl Guix installation, if any.  Error out or warn if they do not match.
AC_DEFUN([GUIX_CHECK_LOCALSTATEDIR], [
  AC_REQUIRE([GUIX_CURRENT_LOCALSTATEDIR])
  if test "x$guix_cv_current_localstatedir" != "xnone"; then
    if test "$guix_cv_current_localstatedir" != "$guix_localstatedir"; then
      case "$localstatedir" in
        NONE|\${prefix}*)
          # User kept the default value---i.e., did not pass '--localstatedir'.
          AC_MSG_ERROR([chosen localstatedir '$guix_localstatedir' does not match \
that of the existing installation '$guix_cv_current_localstatedir'
Installing may corrupt $storedir!
Use './configure --localstatedir=$guix_cv_current_localstatedir'.])
          ;;
        *)
          # User passed an explicit '--localstatedir'.  Assume they know what
          # they're doing.
          AC_MSG_WARN([chosen localstatedir '$guix_localstatedir' does not match \
that of the existing installation '$guix_cv_current_localstatedir'])
          AC_MSG_WARN([installing may corrupt $storedir!])
         ;;
      esac
    fi
  fi])
f='#n777'>777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2015 Steve Sprang <scs@stevesprang.com>
;;; Copyright © 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Efraim Flashner <efraim@flashner.co.il>
;;; Copyright © 2015 Aljosha Papsch <misc@rpapsch.de>
;;; Copyright © 2016 Christine Lemmer-Webber <cwebber@dustycloud.org>
;;; Copyright © 2016 Jessica Tallon <tsyesika@tsyesika.se>
;;; Copyright © 2016 Andreas Enge <andreas@enge.fr>
;;; Copyright © 2016 Lukas Gradl <lgradl@openmailbox.org>
;;; Copyright © 2016, 2019, 2020 Alex Griffin <a@ajgrf.com>
;;; Copyright © 2017 Leo Famulari <leo@famulari.name>
;;; Copyright © 2017, 2018 Clément Lassieur <clement@lassieur.org>
;;; Copyright © 2017–2021 Tobias Geerinckx-Rice <me@tobias.gr>
;;; Copyright © 2017 Jelle Licht <jlicht@fsfe.org>
;;; Copyright © 2017, 2019 Eric Bavier <bavier@member.fsf.org>
;;; Copyright © 2017, 2020-2022 Nicolas Goaziou <mail@nicolasgoaziou.fr>
;;; Copyright © 2017 Manolis Fragkiskos Ragkousis <manolis837@gmail.com>
;;; Copyright © 2017 Rutger Helling <rhelling@mykolab.com>
;;; Copyright © 2018, 2022 Marius Bakke <marius@gnu.org>
;;; Copyright © 2018 Konrad Hinsen <konrad.hinsen@fastmail.net>
;;; Copyright © 2018 Thomas Sigurdsen <tonton@riseup.net>
;;; Copyright © 2018 Arun Isaac <arunisaac@systemreboot.net>
;;; Copyright © 2018 Pierre Neidhardt <mail@ambrevar.xyz>
;;; Copyright © 2018 Amirouche Boubekki <amirouche@hypermove.net>
;;; Copyright © 2018, 2019, 2020 Tim Gesthuizen <tim.gesthuizen@yahoo.de>
;;; Copyright © 2019 Jens Mølgaard <jens@zete.tk>
;;; Copyright © 2019,2022 Tanguy Le Carrour <tanguy@bioneland.org>
;;; Copyright © 2020 Guillaume Le Vaillant <glv@posteo.net>
;;; Copyright © 2020 Brice Waegeneire <brice@waegenei.re>
;;; Copyright © 2020 Jean-Baptiste Note <jean-baptiste.note@m4x.org>
;;; Copyright © 2020 Michael Rohleder <mike@rohleder.de>
;;; Copyright © 2020 Vinicius Monego <monego@posteo.net>
;;; Copyright © 2020 Hartmut Goebel <h.goebel@crazy-compilers.com>
;;; Copyright © 2021 Stefan Reichör <stefan@xsteve.at>
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
;;; Copyright © 2020 Hartmut Goebel <h.goebel@crazy-compilers.com>
;;; Copyright © 2021 David Dashyan <mail@davie.li>
;;; Copyright © 2022 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2022 Maxime Devos <maximedevos@telenet.be>
;;;
;;; This file is part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.

(define-module (gnu packages password-utils)
  #:use-module ((guix licenses) #:prefix license:)
  #:use-module (guix utils)
  #:use-module (guix build-system cmake)
  #:use-module (guix build-system gnu)
  #:use-module (guix build-system go)
  #:use-module (guix build-system trivial)
  #:use-module (guix download)
  #:use-module (guix gexp)
  #:use-module (guix git-download)
  #:use-module (guix packages)
  #:use-module (gnu packages)
  #:use-module (gnu packages admin)
  #:use-module (gnu packages aidc)
  #:use-module (gnu packages authentication)
  #:use-module (gnu packages autotools)
  #:use-module (gnu packages base)
  #:use-module (gnu packages check)
  #:use-module (gnu packages compression)
  #:use-module (gnu packages crypto)
  #:use-module (gnu packages cryptsetup)
  #:use-module (gnu packages curl)
  #:use-module (gnu packages digest)
  #:use-module (gnu packages docbook)
  #:use-module (gnu packages file)
  #:use-module (gnu packages freedesktop)
  #:use-module (gnu packages gettext)
  #:use-module (gnu packages glib)
  #:use-module (gnu packages gnupg)
  #:use-module (gnu packages golang)
  #:use-module (gnu packages gtk)
  #:use-module (gnu packages guile)
  #:use-module (gnu packages kerberos)
  #:use-module (gnu packages libffi)
  #:use-module (gnu packages libusb)
  #:use-module (gnu packages linux)
  #:use-module (gnu packages man)
  #:use-module (gnu packages multiprecision)
  #:use-module (gnu packages ncurses)
  #:use-module (gnu packages nss)
  #:use-module (gnu packages opencl)
  #:use-module (gnu packages perl)
  #:use-module (gnu packages pkg-config)
  #:use-module (gnu packages python)
  #:use-module (gnu packages python-web)
  #:use-module (gnu packages python-xyz)
  #:use-module (gnu packages readline)
  #:use-module (gnu packages ruby)
  #:use-module (gnu packages security-token)
  #:use-module (gnu packages suckless)
  #:use-module (gnu packages tcl)
  #:use-module (gnu packages tls)
  #:use-module (gnu packages qt)
  #:use-module (gnu packages version-control)
  #:use-module (gnu packages wxwidgets)
  #:use-module (gnu packages xdisorg)
  #:use-module (gnu packages xorg)
  #:use-module (gnu packages xml)
  #:use-module (guix build-system python))

(define-public pwgen
  (package
    (name "pwgen")
    (version "2.08")
    (source
     (origin
       (method url-fetch)
       (uri (string-append "mirror://sourceforge/pwgen/pwgen/" version
                           "/pwgen-" version ".tar.gz"))
       (sha256
        (base32 "0yy90pqrr2pszzhb5hxjishq9qc7dqd290amiibqx9fm1b9kvc6s"))))
    (build-system gnu-build-system)
    (arguments
     `(#:tests? #f)) ; no test suite
    (home-page "http://pwgen.sourceforge.net/")
    (synopsis "Password generator")
    (description "Pwgen generates passwords which can be easily memorized by a
human.")
    (license license:gpl2)))

(define-public keepassxc
  (package
    (name "keepassxc")
    (version "2.7.1")
    (source
     (origin
       (method url-fetch)
       (uri (string-append "https://github.com/keepassxreboot/keepassxc"
                           "/releases/download/" version "/keepassxc-"
                           version "-src.tar.xz"))
       (sha256
        (base32 "1ryk2ndv93jb155cp7qkjm7jd8hjy0v5gqvdvbdidhrmdiibl0b0"))))
    (build-system cmake-build-system)
    (arguments
     (list
      #:modules '((guix build cmake-build-system)
                  (guix build qt-utils)
                  (guix build utils))
      #:imported-modules `(,@%cmake-build-system-modules
                           (guix build qt-utils))
      #:configure-flags
      #~(list "-DWITH_XC_ALL=YES"
              "-DWITH_XC_UPDATECHECK=NO")
      #:phases
      #~(modify-phases %standard-phases
          (replace 'check
            (lambda* (#:key tests? #:allow-other-keys)
              (when tests?
                ;; Fails with "TestCli::testClip() Compared values are not the
                ;; same".  That test also requires a phase with (setenv
                ;; "QT_QPA_PLATFORM" "offscreen") in order to work.
                (invoke "ctest" "--exclude-regex" "testcli"))))
          (add-after 'install 'wrap-qt
            (lambda* (#:key inputs #:allow-other-keys)
              (wrap-qt-program "keepassxc" #:output #$output #:inputs inputs))))))
    (native-inputs
     (list qttools-5 ruby-asciidoctor))
    (inputs
     (list argon2
           botan
           libgcrypt
           libsodium                    ; XC_BROWSER
           libusb
           libyubikey                   ; XC_YUBIKEY
           libxi
           libxtst
           minizip
           pcsc-lite
           qrencode
           qtbase-5
           qtsvg-5
           qtx11extras
           quazip-0                     ; XC_KEESHARE
           readline
           yubikey-personalization      ; XC_YUBIKEY
           zlib))
    (home-page "https://www.keepassxc.org")
    (synopsis "Password manager")
    (description "KeePassXC is a password manager or safe which helps you to
manage your passwords in a secure way.  You can put all your passwords in one
database, which is locked with one master key or a key-file which can be stored
on an external storage device.  The databases are encrypted using the
algorithms AES or Twofish.")
    (properties
     '((release-monitoring-url . "https://github.com/keepassxreboot/keepassxc/releases")))
    ;; While various parts of the software are licensed under different licenses,
    ;; the combined work falls under the GPLv3.
    (license license:gpl3)))

(define-public pwsafe
  (package
    (name "pwsafe")
    (version "3.54.1")
    (home-page "https://www.pwsafe.org/")
    (source
     (origin
       (method git-fetch)
       (uri (git-reference
             (url "https://github.com/pwsafe/pwsafe")
             (commit version)))
       (sha256
        (base32 "0d51dlw98mv23nwb0b5jyji8gnb9f5cnig6kivfljl97lmr6lhvf"))
       (file-name (git-file-name name version))))
    (build-system cmake-build-system)
    (native-inputs
     `(("gettext" ,gettext-minimal)
       ("gtest" ,googletest)
       ("perl" ,perl)
       ("zip" ,zip)))
    (inputs `(("curl" ,curl)
              ("file" ,file)
              ("libuuid" ,util-linux "lib")
              ("libxt" ,libxt)
              ("libxtst" ,libxtst)
              ("openssl" ,openssl)
              ("qrencode" ,qrencode)
              ("wxwidgets" ,wxwidgets)
              ("xerces-c" ,xerces-c)))
    (arguments '(#:configure-flags (list "-DNO_GTEST=YES")
                 #:phases (modify-phases %standard-phases
                            (add-after 'unpack 'add-gtest
                              (lambda* (#:key inputs #:allow-other-keys)
                                (chmod "CMakeLists.txt" #o644)
                                (let ((cmake-port (open-file "CMakeLists.txt"
                                                             "a")))
                                  (display "find_package(GTest)
add_subdirectory(src/test)\n" cmake-port)
                                  (close cmake-port)
                                  #t))))))
    (synopsis "Password safe with automatic input and key generation")
    (description "pwsafe is a password manager originally designed by Bruce
Schneier.  It offers a simple UI to manage passwords for different services.
There are other programs that support the file format on different
platforms.")
    (license license:artistic2.0)))

(define-public pwsafe-cli
  (let ((commit "c49a0541b66647ad04d19ddb351d264054c67759")
        (revision "0"))
    (package
      (name "pwsafe-cli")
      (version (git-version "0.2.0" revision commit))
      (source
       (origin
         (method git-fetch)
         (uri (git-reference
               (url "https://github.com/nsd20463/pwsafe")
               (commit commit)))
         (sha256
          (base32
           "0ak09r1l7k57m6pdx468hhzvz0szmaq42vyr575fvsjc8rbrp8qq"))
         (file-name (git-file-name name version))))
      (build-system gnu-build-system)
      (arguments
       ;; FIXME: skip failing test suite (requires write access to /tmp),
       ;; patching path does not help somehow.
       `(#:tests? #f
         #:phases
         (modify-phases %standard-phases
           (replace 'bootstrap
             (lambda _
               (invoke "aclocal")
               (invoke "autoheader")
               (invoke "automake" "--add-missing")
               (invoke "autoconf")
               #t)))))
      (native-inputs
       (list autoconf automake))
      (inputs
       (list libx11 libxmu libxt openssl))
      (home-page "https://github.com/nsd20463/pwsafe")
      (synopsis "CLI password manager")
      (description
       "@command{pwsafe} is a command line tool compatible with
Counterpane's Passwordsafe.")
      (license license:gpl2+))))

(define-public shroud
  (package
    (name "shroud")
    (version "0.1.2")
    (source (origin
              (method url-fetch)
              (uri (string-append "https://files.dthompson.us/shroud/shroud-"
                                  version ".tar.gz"))
              (sha256
               (base32
                "1l2shrhvcwfzkar9qiwb75nhcqmx25iz55lzmz0c187nbjhqzi9p"))))
    (build-system gnu-build-system)
    (native-inputs
     (list pkg-config))
    (arguments
     `(#:modules ((guix build gnu-build-system)
                    (guix build utils)
                    (ice-9 popen)
                    (ice-9 rdelim))
       #:phases
       (modify-phases %standard-phases
         (add-after 'install 'wrap-shroud
           (lambda* (#:key inputs outputs #:allow-other-keys)
             (let* ((out       (assoc-ref outputs "out"))
                    (guile (assoc-ref inputs "guile"))
                    (effective (read-line
                                (open-pipe* OPEN_READ
                                            (string-append guile "/bin/guile")
                                            "-c" "(display (effective-version))")))
                    (ccachedir (string-append out
                                             "/lib/guile/" effective "/site-ccache"))
                    (prog      (string-append out "/bin/shroud")))
               (wrap-program prog
                 `("GUILE_LOAD_COMPILED_PATH" ":" prefix (,ccachedir)))
               #t))))))
    (inputs
     (list guile-2.2 gnupg xclip))
    (synopsis "GnuPG-based secret manager")
    (description "Shroud is a simple secret manager with a command line
interface.  The password database is stored as a Scheme s-expression and
encrypted with a GnuPG key.  Secrets consist of an arbitrary number of
key/value pairs, making Shroud suitable for more than just password storage.
For copying and pasting secrets into web browsers and other graphical
applications, there is xclip integration." )
    (home-page "https://dthompson.us/projects/shroud.html")
    (license license:gpl3+)))

(define-public yapet
  (package
    (name "yapet")
    (version "2.5")
    (source
     (origin
       (method url-fetch)
       (uri (string-append "https://yapet.guengel.ch/downloads/yapet-"
                           version ".tar.xz"))
       (sha256
        (base32 "0hpibsdry259cmvps35isr6jn9cd9fsk3r1h0ppjx9zxfrpqwldg"))))
    (build-system gnu-build-system)
    (arguments
     `(#:configure-flags
       (list (string-append "--docdir=" (assoc-ref %outputs "out")
                            "/share/doc",name "-" ,version))))
    (inputs
     (list argon2 ncurses openssl))
    (native-inputs
     (list cppunit pkg-config))
    (synopsis "Yet Another Password Encryption Tool")
    (description "YAPET is a text based password manager using the Blowfish
encryption algorithm.  Because of its small footprint and very few library
dependencies, it is suited for installing on desktop and server systems alike.
The text based user interface allows you to run YAPET easily in a Secure Shell
session.  Two companion utilities enable users to convert CSV files to YAPET
and vice versa.")
    (home-page "https://yapet.guengel.ch/")
    (license license:gpl3+)))

(define-public cracklib
  (package
    (name "cracklib")
    (version "2.9.7")
    (source
     (origin
       (method url-fetch)
       (uri (string-append "https://github.com/cracklib/cracklib/"
                           "releases/download/v" version "/"
                           "cracklib-" version ".tar.bz2"))
       (sha256
        (base32 "1rimpjsdnmw8f5b7k558cic41p2qy2n2yrlqp5vh7mp4162hk0py"))))
    (build-system gnu-build-system)
    (arguments
     `(#:phases
       (modify-phases %standard-phases
         (add-after 'install 'install-dict
           (lambda* (#:key make-flags #:allow-other-keys)
             (begin
               (chmod (string-append "util/cracklib-format") #o755)
               (apply invoke "make" "dict" make-flags)
               #t))))))
    (synopsis "Password checking library")
    (home-page "https://github.com/cracklib/cracklib")
    (description
     "CrackLib is a library containing a C function which may be used in a
@command{passwd}-like program.  The idea is simple: try to prevent users from
choosing passwords that could easily be guessed (or \"cracked\") by filtering
them out, at the source.")
    (license license:lgpl2.1)))

(define-public libpwquality
  (package
    (name "libpwquality")
    (version "1.4.4")
    (source (origin
              (method url-fetch)
              (uri (list
                    (string-append "https://github.com/libpwquality/libpwquality"
                                   "/releases/download/libpwquality-" version
                                   "/libpwquality-" version ".tar.bz2")
                    (string-append "https://launchpad.net/libpwquality/trunk/"
                                   version "/+download/"
                                   "libpwquality-" version ".tar.bz2")))
              (sha256
               (base32
                "0id5a8bi8xnjg11g9vzrl2xbpx65mfxclxcvis7zx1v8vhisyfyl"))))
    (build-system gnu-build-system)
    (arguments
     `(#:phases
       (modify-phases %standard-phases
         (add-before 'configure 'set-LDFLAGS
           (lambda* (#:key inputs outputs #:allow-other-keys)
             (setenv "LDFLAGS"
                     (string-append
                      "-Wl,-rpath="
                      (assoc-ref outputs "out") "/lib"))
             #t)))))
    (native-inputs
     `(("python" ,python-wrapper)))
    (inputs
     (list cracklib))
    (synopsis "Password quality checker")
    (home-page "https://github.com/libpwquality/libpwquality")
    (description
     "Libpwquality is a library for password quality checking and generation of
random passwords that pass the checks.")
    (license license:gpl2+)))

(define-public assword
  (package
    (name "assword")
    (version "0.11")
    (source (origin
              (method url-fetch)
              (uri (list
                    (string-append
                     "http://http.debian.net/debian/pool/main/a/assword/"
                     "assword_" version ".orig.tar.gz")))
              (sha256
               (base32
                "03gkb6kvsghznbcw5l7nmrc6mn3ixkjd5jcs96ni4zs9l47jf7yp"))))
    (arguments
     `(;; irritatingly, tests do run but not there are two problems:
       ;;  - "import gtk" fails for unknown reasons here despite it the
       ;;    program working (indeed, I've found I have to do a logout and log
       ;;    back in in after an install order for some mumbo jumbo environment
       ;;    variable mess to work with pygtk and assword... what's up with
       ;;    that?)
       ;;  - even when the tests fail, they don't return a nonzero status,
       ;;    so I'm not sure how to programmatically get that information
       #:tests? #f
       #:phases
       (modify-phases %standard-phases
         (add-after 'install 'wrap-assword
           (lambda* (#:key outputs #:allow-other-keys)
             (let ((prog            (string-append
                                     (assoc-ref outputs "out")
                                     "/bin/assword"))
                   (gi-typelib-path (getenv "GI_TYPELIB_PATH")))
               (wrap-program prog
                 `("GI_TYPELIB_PATH" ":" prefix (,gi-typelib-path)))
               #t)))
         (add-after 'install 'manpage
           (lambda* (#:key outputs #:allow-other-keys)
             (invoke "make" "assword.1")
             (install-file
              "assword.1"
              (string-append (assoc-ref outputs "out") "/share/man/man1")))))))
    (build-system python-build-system)
    (native-inputs
     (list txt2man))
    (inputs
     (list gtk+ python-xdo python-gpg python-pygobject))
    (propagated-inputs
     (list xclip))
    (home-page "https://finestructure.net/assword/")
    (synopsis "Password manager")
    (description "assword is a simple password manager using GPG-wrapped
JSON files.  It has a command line interface as well as a very simple
graphical interface, which can even \"type\" your passwords into
any X11 window.")
    (license license:gpl3+)))

(define-public password-store
  (package
    (name "password-store")
    (version "1.7.4")
    (source (origin
              (method git-fetch)
              (uri (git-reference
                    (url "git://git.zx2c4.com/password-store")
                    (commit version)))
              (sha256
               (base32
                "17zp9pnb3i9sd2zn9qanngmsywrb7y495ngcqs6313pv3gb83v53"))
              (patches (search-patches "password-store-tree-compat.patch"))
              (file-name (git-file-name name version))))
    (build-system gnu-build-system)
    (arguments
     '(#:phases
       (modify-phases %standard-phases
         (delete 'configure)
         (delete 'build)
         (add-before 'install 'patch-system-extension-dir
           (lambda* (#:key outputs #:allow-other-keys)
             (let* ((out (assoc-ref outputs "out"))
                    (extension-dir (string-append out "/lib/password-store/extensions")))
               (substitute* "src/password-store.sh"
                 (("^SYSTEM_EXTENSION_DIR=.*$")
                  ;; lead with whitespace to prevent 'make install' from
                  ;; overwriting it again
                  (string-append " SYSTEM_EXTENSION_DIR=\""
                                 "${PASSWORD_STORE_SYSTEM_EXTENSION_DIR:-"
                                 extension-dir
                                 "}\"\n"))))))
         (add-before 'install 'patch-passmenu-path
           ;; FIXME Wayland support requires ydotool and dmenu-wl packages
           ;; We are ignoring part of the script that gets executed if
           ;; WAYLAND_DISPLAY env variable is set, leaving dmenu-wl and ydotool
           ;; commands as is.
           (lambda* (#:key inputs #:allow-other-keys)
             (substitute* "contrib/dmenu/passmenu"
               (("dmenu=dmenu\n")
                (string-append "dmenu="
                               (search-input-file inputs "/bin/dmenu")
                               "\n"))
               (("xdotool=\"xdotool")
                (string-append "xdotool=\""
                               (search-input-file inputs "/bin/xdotool"))))))
         (add-after 'install 'install-passmenu
           (lambda* (#:key outputs #:allow-other-keys)
             (let* ((out (assoc-ref outputs "out"))
                    (bin (string-append out "/bin")))
               (install-file "contrib/dmenu/passmenu" bin))))
         (add-after 'install 'wrap-path
           (lambda* (#:key inputs outputs #:allow-other-keys)
             (let* ((out (assoc-ref outputs "out"))
                    (requisites '("getopt" "git" "gpg" "qrencode" "sed"
                                  "tree" "which" "wl-copy" "xclip"))
                    (path (map (lambda (pkg)
                                 (dirname (search-input-file
                                           inputs (string-append "/bin/" pkg))))
                               requisites)))
               (wrap-program (string-append out "/bin/pass")
                 `("PATH" ":" prefix (,(string-join path ":"))))))))
       #:make-flags (list "CC=gcc" (string-append "PREFIX=" %output)
                          "WITH_ALLCOMP=yes"
                          (string-append "BASHCOMPDIR="
                                         %output "/etc/bash_completion.d"))
       ;; Parallel tests may cause a race condition leading to a
       ;; timeout in some circumstances.
       #:parallel-tests? #f
       #:test-target "test"))
    (native-search-paths
     (list (search-path-specification
            (variable "PASSWORD_STORE_SYSTEM_EXTENSION_DIR")
            (separator #f)             ;single entry
            (files '("lib/password-store/extensions")))))
    (inputs
     (list dmenu
           util-linux
           git
           gnupg
           qrencode
           sed
           tree
           which
           wl-clipboard
           xclip
           xdotool))
    (home-page "https://www.passwordstore.org/")
    (synopsis "Encrypted password manager")
    (description "Password-store is a password manager which uses GnuPG to
store and retrieve passwords.  The tool stores each password in its own
GnuPG-encrypted file, allowing the program to be simple yet secure.
Synchronization is possible using the integrated git support, which commits
changes to your password database to a git repository that can be managed
through the pass command.")
    (license license:gpl2+)))

(define-public pass-otp
  (package
    (name "pass-otp")
    (version "1.2.0")
    (source
     (origin
       (method url-fetch)
       (uri
        (string-append "https://github.com/tadfisher/pass-otp/releases/"
                       "download/v" version "/pass-otp-" version ".tar.gz"))
       (sha256
        (base32
         "0rrs3iazq80dn0wbl20xkh270428jd8l99m5gd7hl93s4r4sc82p"))))
    (build-system gnu-build-system)
    (arguments
     '(#:make-flags
       (let* ((out      (assoc-ref %outputs "out"))
              (bashcomp (string-append out "/etc/bash_completion.d")))
         (list (string-append "PREFIX=" %output)
               (string-append "BASHCOMPDIR=" bashcomp)))
       #:phases
       (modify-phases %standard-phases
         (delete 'configure)
         (add-after 'build 'patch-oath-path
           (lambda* (#:key inputs #:allow-other-keys)
             (substitute* "otp.bash"
               (("^OATH=.*$")
                (string-append
                 "OATH="
                 (assoc-ref inputs "oath-toolkit")
                 "/bin/oathtool\n")))
             #t)))
       #:test-target "test"))
    (inputs
     (list oath-toolkit))
    (native-inputs
     (list password-store expect git gnupg which))
    (home-page "https://github.com/tadfisher/pass-otp")
    (synopsis "Pass extension for managing one-time-password (OTP) tokens")
    (description
     "Pass OTP is an extension for password-store that allows adding
one-time-password (OTP) secrets, generating OTP codes, and displaying secret
key URIs using the standard otpauth:// scheme.")
    (license license:gpl3+)))

(define-public qtpass
  (package
    (name "qtpass")
    (version "1.3.2")
    (source
     (origin
       (method git-fetch)
       (uri (git-reference
             (url "https://github.com/IJHack/QtPass")
             (commit (string-append "v" version))))
       (file-name (git-file-name name version))
       (sha256
        (base32
         "0748hjvhjrybi33ci3c8hcr74k9pdrf5jv8npf9hrsrmdyy1kr9x"))))
    (build-system gnu-build-system)
    (arguments
     `(#:modules ((guix build gnu-build-system)
                  (guix build qt-utils)
                  (guix build utils))
       #:imported-modules (,@%gnu-build-system-modules
                            (guix build qt-utils))
       #:phases
       (modify-phases %standard-phases
         (replace 'configure
           (lambda* (#:key inputs outputs #:allow-other-keys)
             (let ((out (assoc-ref outputs "out")))
               ;; lupdate/lrelease need to find qmake.
               (setenv "QMAKE" "qmake")
               ;; qmake needs to find lrelease/lupdate.
               (invoke "qmake"
                       "QMAKE_LRELEASE=lrelease"
                       "QMAKE_LUPDATE=lupdate"
                       (string-append "PREFIX=" out)))))
         (add-after 'configure 'reset-resource-timestamps
           ;; Reset timestamps on localization files for a reproducible build.
           (lambda _
             (with-directory-excursion "localization"
               (for-each (lambda (file)
                           (let* ((base (basename file ".qm"))
                                  (src (string-append base ".ts"))
                                  (st (stat src)))
                             (set-file-time file st)))
                         (find-files "." ".*\\.qm")))
             #t))
         (add-after 'install 'install-auxilliary
           ;; Install man-page, icon and .desktop file.
           (lambda* (#:key inputs outputs #:allow-other-keys)
             (let* ((out (assoc-ref outputs "out"))
                    (applications (string-append out "/share/applications"))
                    (icons (string-append out "/share/icons/hicolor/scalable/apps"))
                    (man (string-append out "/share/man/man1")))
               (install-file "qtpass.desktop" applications)
               (install-file "artwork/icon.svg" icons)
               (rename-file (string-append icons "/icon.svg")
                            (string-append icons "/qtpass-icon.svg"))
               (install-file "qtpass.1" man)
               #t)))
         (add-after 'install 'wrap-qt
           (lambda* (#:key outputs inputs #:allow-other-keys)
             (let ((out (assoc-ref outputs "out")))
               (wrap-qt-program "qtpass" #:output out #:inputs inputs))
             #t))
         (add-before 'check 'check-setup
           ;; Make Qt render "offscreen", required for tests.
           (lambda _
             (setenv "QT_QPA_PLATFORM" "offscreen")
             #t)))))
    (native-inputs
     (list qttools-5))
    (inputs
     (list qtbase-5 qtsvg-5))
    (home-page "https://qtpass.org")
    (synopsis "GUI for password manager password-store")
    (description
     "Qt-based graphical user interface for the password manager
password-store also known as pass.  Can use either pass or gpg to interact
with password-store files.  Features configurable password generation,
templates, clipboard handling, and per folder settings for multi-recipient
encryption.")
    (license license:gpl3+)))

(define-public rofi-pass
  (package
    (name "rofi-pass")
    (version "2.0.2")
    (source
     (origin
       (method url-fetch)
       (uri
        (string-append "https://raw.githubusercontent.com/carnager/rofi-pass/"
                       version "/rofi-pass"))
       (sha256
        (base32 "0msldkndqp40nx1s5s7ggcr97ir4nshpmnyzvj5hqw1l7m3gvw6j"))
       (file-name name)))
    (build-system trivial-build-system)
    (arguments
     `(#:modules ((guix build utils))
       #:builder
       (begin
         (use-modules (guix build utils))
         (let ((source (string-append (assoc-ref %build-inputs "source")))
               (script "rofi-pass")
               (out (assoc-ref %outputs "out")))
           (copy-file source script)
           (chmod script #o555)
           (install-file script (string-append out "/bin"))))))
    (propagated-inputs
     (list password-store rofi xdotool))
    (home-page "https://github.com/carnager/rofi-pass")
    (synopsis "Rofi frontend for password-store")
    (description "Rofi-pass provides a way to manipulate information stored
using password-store through rofi interface:
@enumerate
@item open URLs of entries with hotkey;
@item type any field from entry;
@item auto-typing of user and/or password fields;
@item auto-typing username based on path;
@item auto-typing of more than one field, using the autotype entry;
@item bookmarks mode (open stored URLs in browser, default: Alt+x).
@end enumerate")
    (license license:gpl3)))

(define-public tessen
  (package
    (name "tessen")
    (version "2.1.0")
    (source (origin
              (method git-fetch)
              (uri (git-reference
                    (url "https://github.com/ayushnix/tessen/")
                    (commit (string-append "v" version))))
              (file-name (git-file-name name version))
              (sha256
               (base32
                "1ddsjhzp1qy3jfhxlrzcxgp0gza234yc0sdlngwa3xdj0wr40zs0"))))
    (build-system gnu-build-system)
    (arguments
     (list #:tests?
           #f ;no tests
           #:phases
           #~(modify-phases %standard-phases
               (add-after 'unpack 'patch-wtype-path
                 (lambda* (#:key inputs #:allow-other-keys)
                   (substitute* "tessen"
                     (("wtype") (search-input-file inputs "/bin/wtype")))))
               (delete 'configure)) ;no configure script
           #:make-flags
           #~(list (string-append "PREFIX="
                                  #$output))))
    (native-inputs (list scdoc))
    (inputs (list wtype))
    (home-page "https://github.com/ayushnix/tessen")
    (synopsis "Frontend for password-store and gopass")
    (description "Tessen is a bash script that can autotype and copy data
from password-store and gopass files.")
    (license license:gpl2+)))

(define-public browserpass-native
  (package
    (name "browserpass-native")
    (version "3.0.7")
    (source
     (origin
       (method git-fetch)
       (uri (git-reference
             (url "https://github.com/browserpass/browserpass-native")
             (commit version)))
       (file-name (git-file-name name version))
       (sha256
        (base32
         "1jkjslbbac49xjyjkc2b07phdm3i64z40kh6h55cl22dxjmpp1nb"))))
    (build-system go-build-system)
    (arguments
     `(#:import-path "github.com/browserpass/browserpass-native"
       #:install-source? #f
       #:phases
       (modify-phases %standard-phases
         (add-before 'build 'patch-makefile
           (lambda* (#:key outputs #:allow-other-keys)
             (let ((out (assoc-ref outputs "out")))
               ;; This doesn't go in #:make-flags because the Makefile itself
               ;; gets installed.
               (substitute*
                   "src/github.com/browserpass/browserpass-native/Makefile"
                 (("PREFIX \\?= /usr")
                  (string-append "PREFIX ?= " out)))
               #t)))
         (add-before 'build 'configure
           (lambda _
               (with-directory-excursion
                   "src/github.com/browserpass/browserpass-native"
                 (invoke "make" "configure"))
             #t))
         (replace 'build
           (lambda _
               (with-directory-excursion
                   "src/github.com/browserpass/browserpass-native"
                 (invoke "make"))
             #t))
         (replace 'install
           (lambda _
             (with-directory-excursion
                 "src/github.com/browserpass/browserpass-native"
               (invoke "make" "install"))
             #t))
         (add-after 'install 'wrap-executable
           (lambda* (#:key inputs outputs #:allow-other-keys)
             (let ((out (assoc-ref outputs "out"))
                   (gnupg (assoc-ref inputs "gnupg")))
               (wrap-program (string-append out "/bin/browserpass")
                 `("PATH" ":" prefix
                   (,(string-append gnupg "/bin"))))
               #t))))))
    (native-inputs
     (list which))
    (inputs
     (list gnupg go-github-com-mattn-go-zglob
           go-github-com-rifflock-lfshook go-github-com-sirupsen-logrus
           go-golang-org-x-sys))
    (home-page "https://github.com/browserpass/browserpass-native")
    (synopsis "Browserpass native messaging host")
    (description "Browserpass is a browser extension for pass, a
UNIX-based password store manager.  It allows you to auto-fill or copy to
clipboard credentials for the current domain, protecting you from phishing
attacks.

This package only contains the Browserpass native messaging host.  You must
also install the browser extension for GNU IceCat or ungoogled-chromium
separately.")
    (license license:isc)))

(define-public argon2
  (package
    (name "argon2")
    (version "20190702")
    (source
     (origin
       (method git-fetch)
       (uri (git-reference
              (url "https://github.com/P-H-C/phc-winner-argon2")
              (commit version)))
       (file-name (git-file-name name version))
       (sha256
        (base32
         "01rwanr4wmr9vm6c712x411wig543q195z2icn388z892a93lc7p"))))
    (build-system gnu-build-system)
    (arguments
     `(#:test-target "test"
       #:make-flags (list "CC=gcc"
                          (string-append "PREFIX=" (assoc-ref %outputs "out"))
                          "LIBRARY_REL=lib"
                          (string-append "ARGON2_VERSION=" ,version)
                          "OPTTEST=1")  ; disable CPU optimization
       #:phases
       (modify-phases %standard-phases
         (delete 'configure))))         ; No configure script.
    (home-page "https://www.argon2.com/")
    (synopsis "Password hashing library")
    (description "Argon2 provides a key derivation function that was declared
winner of the 2015 Password Hashing Competition.")
    ;; Argon2 is dual licensed under CC0 and ASL 2.0.  Some of the source
    ;; files are CC0 only; see README.md and LICENSE for details.
    (license (list license:cc0 license:asl2.0))))

(define-public pass-git-helper
  (package
    (name "pass-git-helper")
    (version "1.1.0")
    (source
     (origin
       (method git-fetch)
       (uri (git-reference
              (url "https://github.com/languitar/pass-git-helper")
              (commit (string-append "v" version))))
       (file-name (git-file-name name version))
       (sha256
        (base32
         "18nvwlp0w4aqj268wly60rnjzqw2d8jl0hbs6bkwp3hpzzz5g6yd"))))
    (build-system python-build-system)
    (arguments
     `(#:phases
       (modify-phases %standard-phases
         (add-before 'build 'patch-pass-path
           (lambda* (#:key inputs #:allow-other-keys)
             (let* ((password-store (assoc-ref inputs "password-store"))
                    (pass (string-append password-store "/bin/pass")))
               (substitute* '("passgithelper.py"
                              "test_passgithelper.py")
                 (("'pass'") (string-append "'" pass "'")))
               #t)))
         (replace 'check
           (lambda _
             (setenv "HOME" (getcwd))
             (invoke "pytest"))))))
    (inputs
     (list python-pyxdg password-store))
    (native-inputs
     (list python-pytest python-pytest-mock))
    (home-page "https://github.com/languitar/pass-git-helper")
    (synopsis "Git credential helper interfacing with pass")
    (description "pass-git-helper is a git credential helper which
uses pass, the standard unix password manager, as the credential backend for
your git repositories.  This is achieved by explicitly defining mappings
between hosts and entries in the password store.")
    (license license:lgpl3+)))

(define-public john-the-ripper-jumbo
  (let ((official-version "1.9.0")
        (jumbo-version "1"))
    (package
      (name "john-the-ripper-jumbo")
      (version (string-append official-version "-" jumbo-version))
      (source
       (origin
         (method url-fetch)
         (uri (string-append "http://www.openwall.com/john/j/john-"
                             official-version "-jumbo-" jumbo-version ".tar.xz"))
         (sha256
          (base32
           "0fvz3v41hnaiv1ggpxanfykyfjq79cwp9qcqqn63vic357w27lgm"))))
      (build-system gnu-build-system)
      (native-inputs
       (list perl))
      (inputs
       (list gmp
             libpcap
             nss
             openssl
             python-wrapper
             ruby                       ; For genincstats.rb
             zlib))
      (arguments
       `(#:configure-flags
         (list "--with-systemwide"
               ;; Do not test for instruction set in configure, and do not
               ;; pass '-march=native' to gcc:
               "--disable-native-tests"
               "--disable-native-march"
               ,(string-append
                 "--enable-simd="
                 (let ((system (or (%current-target-system)
                                   (%current-system))))
                   (cond
                    ((or (string-prefix? "x86_64" system)
                         (string-prefix? "i686" system)) "sse2")
                    ((string-prefix? "aarch" system) "neon")
                    (else "no")))))
         #:phases
         (modify-phases %standard-phases
           (add-before 'configure 'chdir-src
             (lambda _ (chdir "src") #t))
           (replace 'install
             (lambda _
               (let ((bindir (string-append %output "/bin"))
                     (docdir (string-append %output "/share/doc/john"))
                     (execdir (string-append %output "/libexec/john"))
                     (datadir (string-append %output "/share/john"))
                     (install-file-to (lambda (dir)
                                        (lambda (f) (install-file f dir))))
                     (symlink? (lambda (_ s) (eq? (stat:type s) 'symlink))))
                 (with-directory-excursion "../run"
                   (for-each (install-file-to bindir)
                             (cons*
                              "john" "makechr" "cprepair" "SIPdump" "tgtsnarf"
                              "genmkvpwd" "mkvcalcproba" "calc_stat" "raw2dyna"
                              (find-files "." "(to|2)?john(-[^.]*)?$")))
                   (for-each (lambda (f) ; Install symlinked aliases
                               (let ((tgt (string-append bindir "/" (basename f))))
                                 ;; The use of install-file above dereferences
                                 ;; symlinks.  We'd rather have the symlinks
                                 ;; for clarity, so remove tgt before linking.
                                 (when (file-exists? tgt) (delete-file tgt))
                                 (symlink "john" tgt)))
                             (find-files "." symlink?))
                   (for-each (install-file-to execdir)
                             (cons* "mailer" "benchmark-unify" "relbench"
                                    (find-files "." ".*\\.js")))
                   (for-each (lambda (f)
                               (let* ((base (basename f))
                                      (name (substring base 0 (string-index base #\.)))
                                      (link (string-append bindir "/" name)))
                                 (install-file f execdir)
                                 (when (and (executable-file? f)
                                            (not (file-exists? link)))
                                   (symlink (string-append execdir "/" base) link))))
                             (find-files "." ".*\\.(pl|py|rb|lua)"))
                   (for-each (install-file-to datadir)
                             (append (find-files "." "(stats|dictionary.*)")
                                     (find-files "." "(.*\\.chr|.*\\.lst)")
                                     (find-files "." ".*\\.conf")))
                   (copy-recursively "rules" (string-append datadir "/rules")))
                 (copy-recursively "../doc" docdir))))
           (delete 'check) ; Tests need installed .conf files; move after install
           (add-after 'install 'check
             (lambda args
               (setenv "HOME" "/tmp")   ; Some tests need to write to ~/.john
               (setenv "OMP_NUM_THREADS" (number->string (parallel-job-count)))
               (apply (assoc-ref %standard-phases 'check) args))))))
      (home-page "http://www.openwall.com/john/")
      (synopsis "Password cracker")
      (description "John the Ripper is a fast password cracker.  Its primary
purpose is to detect weak Unix passwords.  Besides several @code{crypt}
password hash types most commonly found on various Unix systems, supported out
of the box are Windows LM hashes, plus lots of other hashes and ciphers.  This
is the community-enhanced, \"jumbo\" version of John the Ripper.")
      (license license:gpl2+))))

(define-public fpm2
  (package
    (name "fpm2")
    (version "0.79")
    (source (origin
              (method url-fetch)
              (uri (string-append "https://als.regnet.cz/fpm2/download/fpm2-"
                                  version ".tar.bz2"))
              (sha256
               (base32
                "19sdy1lygfhkg5nxi2w9a4d9kwvw24nxp0ix0p0lz91qpvk9qpnm"))))
    (build-system gnu-build-system)
    (inputs `(("gtk2" ,gtk+-2)
              ("gnupg" ,gnupg)
              ("libxml2" ,libxml2)))
    (native-inputs (list pkg-config intltool))
    (arguments
     `(#:configure-flags '("CFLAGS=-O2 -g -fcommon")
       #:phases
       (modify-phases %standard-phases
         (add-before 'configure 'pre-configure
           ;; The file po/POTFILES.in ends up missing for some reason in
           ;; both nix and guix builds. Adding the file with contents
           ;; found during troubleshooting.
           (lambda _
             (call-with-output-file "po/POTFILES.in"
               (lambda (port)
                 (format port "data/fpm2.desktop.in
data/fpm2.desktop.in.in
fpm2.glade
src/callbacks.c
src/fpm.c
src/fpm_file.c
src/interface.c
src/support.c
fpm2.glade
")))
             #t)))))
    (synopsis "Manage, generate and store passwords encrypted")
    (description "FPM2 is GTK2 port from Figaro's Password Manager
originally developed by John Conneely, with some new enhancements.

Upstream development seems to have stopped.  It is therefore recommended
to use a different password manager.")
    (home-page "https://als.regnet.cz/fpm2/")
    (license license:gpl2+)))

(define-public pass-rotate
  (package
    (name "pass-rotate")
    (version "0.1")
    (source
      (origin
        (method git-fetch)
        (uri (git-reference
               (url "https://github.com/ddevault/pass-rotate")
               (commit version)))
        (file-name (git-file-name name version))
        (sha256
         (base32
          "1m067vvdlc85csbpkp8aw4s3ags7q8s3jszrr32kmj9qhk5c254f"))))
    (build-system python-build-system)
    (inputs
     (list python-beautifulsoup4 python-docopt python-html5lib
           python-requests))
    (home-page "https://github.com/ddevault/pass-rotate")
    (synopsis "Rotate password on online services")
    (description "pass-rotate is a command line utility and python library for
rotating passwords on various web services.  It makes it easier to rotate your
passwords, one at a time or in bulk, when security events or routine upkeep of
your online accounts makes it necessary.")
    (license license:expat)))

(define-public hashcat
  (package
    (name "hashcat")
    (version "6.2.5")
    (source (origin
              (method url-fetch)
              (uri (string-append "https://hashcat.net/files/hashcat-" version
                                  ".tar.gz"))
              (sha256
               (base32
                "0sc96xcsc20xd4fyby3i45nm9as3hl4nhk9snkvmk5l9mpbrjs3g"))
              (modules '((guix build utils)))
              ;; Delete bundled libraries.
              (snippet
               ;; TODO: Unbundle LZMA-SDK as well
               #~(for-each delete-file-recursively
                           '("deps/zlib" "deps/xxHash" "deps/OpenCL-Headers")))))
    (inputs (list minizip opencl-headers xxhash zlib))
    (build-system gnu-build-system)
    (arguments
     (list #:tests? #f ;no tests
           #:make-flags #~(list (string-append "PREFIX=" #$output)
                                (string-append "AR=" #$(ar-for-target))
                                (string-append "CC=" #$(cc-for-target))
                                (string-append "USE_SYSTEM_ZLIB=1")
                                (string-append "USE_SYSTEM_OPENCL=1")
                                (string-append "USE_SYSTEM_XXHASH=1"))
           #:phases #~(modify-phases %standard-phases
                        (add-after 'unpack 'fix-reproducibility
                          (lambda _
                            (substitute* "src/Makefile"
                              (("\\$\\(shell date \\+%s\\)")
                               "0"))))
                        (delete 'configure))))
    (home-page "https://hashcat.net/hashcat/")
    (synopsis "Advanced password recovery utility")
    (description
     "Hashcat is an password recovery utility, supporting five
unique modes of attack for over 200 highly-optimized hashing algorithms.
Hashcat currently supports CPUs, GPUs, and other hardware accelerators on
Linux, Windows, and macOS, and has facilities to help enable distributed
password cracking.")
    (license license:expat)))

(define-public hashcat-utils
  (package
    (name "hashcat-utils")
    (version "1.9")
    (source
     (origin
       (method url-fetch)
       (uri (string-append "https://github.com/hashcat/hashcat-utils/releases/"
                           "download/v" version "/"
                           "hashcat-utils-" version ".7z"))
       (sha256
        (base32 "0kq555kb338691qd7zjmi8vhq4km3apnsl2w63zh0igwzcjx6lx1"))))
    (native-inputs
     (list p7zip))
    (inputs
     (list perl))
    (build-system gnu-build-system)
    (arguments
     `(#:tests? #f                      ;no tests
       #:make-flags (list "CC=gcc"
                          ;; Upstream bug(?): "make all" seems to remove the
                          ;; Perl scripts from the source.
                          "native")
       #:phases
       (modify-phases %standard-phases
         (replace 'unpack
           (lambda* (#:key source #:allow-other-keys)
             (invoke "7z" "x" source)
             (chdir (string-append "hashcat-utils-" ,version "/src"))
             #t))
         (delete 'configure)
         (replace 'install
           (lambda* (#:key outputs #:allow-other-keys)
             (let ((out (string-append (assoc-ref outputs "out") "/bin")))
               (mkdir-p out)
               (for-each
                (lambda (file)
                  (copy-file file (string-append out "/"
                                                 (basename file ".bin"))))
                (find-files "." "\\.bin$"))
               (for-each
                (lambda (file)
                  (copy-file file (string-append out "/"
                                                 (basename file ".pl"))))
                (find-files "../bin" "\\.pl$"))
               #t))))))
    (home-page "https://github.com/hashcat/hashcat-utils/")
    (synopsis "Small utilities that are useful in advanced password cracking")
    (description "Hashcat-utils are a set of small utilities that are useful
in advanced password cracking.  They all are packed into multiple stand-alone
binaries.  All of these utils are designed to execute only one specific
function.  Since they all work with @code{STDIN} and @code{STDOUT} you can
group them into chains.")
    (license license:expat)))

(define-public bruteforce-luks
  (package
    (name "bruteforce-luks")
    (version "1.4.0")
    (source
     (origin
       (method url-fetch)
       (uri (string-append "https://github.com/glv2/bruteforce-luks/releases/download/"
                           version
                           "/bruteforce-luks-"
                           version
                           ".tar.lz"))
       (sha256
        (base32 "0yawrlbbklhmvwr99wm7li3r0d5kxvpkwf33a12rji7z0ya5p340"))))
    (build-system gnu-build-system)
    (native-inputs
     (list lzip))
    (inputs
     (list cryptsetup))
    (synopsis "LUKS encrypted volume cracker")
    (description
     "This is a cracker for LUKS encrypted volumes.  It can be used either in
exhaustive mode to try every password given a charset or in dictionary mode to
try every password contained in a file.")
    (home-page "https://github.com/glv2/bruteforce-luks")
    (license license:gpl3+)))

(define-public makepasswd
  (let ((commit "3545d57d3a589a392d7eb0df36a5286785345c9e")
        (revision "1"))
    (package
      (name "makepasswd")
      (version (git-version "0.5.4" revision commit))
      (source
       (origin
         (method git-fetch)
         (uri (git-reference
               (url "https://github.com/khorben/makepasswd")
               (commit commit)))
         (file-name (git-file-name name version))
         (sha256
          (base32 "0lspqyyxbk6h28yxnp7pd5aib161vrkzgasam5jpzn35n1jacx2j"))))
      (build-system gnu-build-system)
      (native-inputs
       (list pkg-config libxslt libxml2 docbook-xsl docbook-xml))
      (inputs
       (list openssl))
      (arguments
       `(#:phases
         (modify-phases %standard-phases
           (delete 'configure))
         #:make-flags (list "CC=gcc"
                            (string-append "PREFIX=" (assoc-ref %outputs "out")))
         #:tests? #f))  ;no tests
      (synopsis "Generate (pseudo-)random passwords and hashes")
      (description
       "Makepasswd is a program that generates pseudo-random passwords of a
desired length.  It can also generate their corresponding hashes for a given
encryption algorithm if so desired.")
      (home-page "https://github.com/khorben/makepasswd")
      (license license:gpl3))))

(define-public pass-tomb
  (package
    (name "pass-tomb")
    (version "1.2")
    (source
     (origin
       (method git-fetch)
       (uri (git-reference
             (url "https://github.com/roddhjav/pass-tomb")
             (commit (string-append "v" version))))
       (file-name (git-file-name name version))
       (sha256
        (base32 "1qj7vx7svk1ljwihj3kv310k17mafnf919n30n4qn1yxmmsvj924"))))
    (build-system gnu-build-system)
    (arguments
     `(#:make-flags
       (let ((out (assoc-ref %outputs "out")))
         (list (string-append "PREFIX=" out)
               (string-append "BASHCOMPDIR=" out "/etc/bash_completion.d")))
       #:test-target "tests"
       ;; tests are very dependent on system state (swap partition) and require
       ;; access to /tmp/zsh which is not in the build container.
       #:tests? #f
       #:phases
       (modify-phases %standard-phases
         (add-after 'unpack 'set-tomb-path
           (lambda* (#:key inputs #:allow-other-keys)
             (let ((tomb (assoc-ref inputs "tomb")))
               (substitute* "tomb.bash"
                 ((":-tomb")
                  (string-append ":-" tomb "/bin/tomb"))))))
         (delete 'configure))))
    (inputs
     (list tomb))
    (home-page "https://github.com/roddhjav/pass-tomb")
    (synopsis "Pass extension keeping the tree of passwords encrypted")
    (description "Pass-tomb provides a convenient solution to put your
password store in a Tomb and then keep your password tree encrypted when you
are not using it.  It uses the same GPG key to encrypt passwords and tomb,
therefore you don't need to manage more key or secret.  Moreover, you can ask
pass-tomb to automatically close your store after a given time.")
    (license license:gpl3+)))