aboutsummaryrefslogtreecommitdiff
path: root/overlays
diff options
context:
space:
mode:
Diffstat (limited to 'overlays')
-rw-r--r--overlays/bitlbee-discord/default.nix12
-rw-r--r--overlays/bitlbee/bitlbee_long_nicks.patch56
-rw-r--r--overlays/bitlbee/default.nix5
-rw-r--r--overlays/bonfire/default.nix36
-rw-r--r--overlays/bugwarrior/default.nix5
-rw-r--r--overlays/bugwarrior/mantisbt.patch379
-rw-r--r--overlays/bundix/default.nix7
-rw-r--r--overlays/databases/mysql/default.nix24
-rw-r--r--overlays/databases/postgresql/default.nix8
-rw-r--r--overlays/default.nix48
-rw-r--r--overlays/doing/default.nix10
-rw-r--r--overlays/dwm/default.nix7
-rw-r--r--overlays/dwm/dwm_config.h98
-rw-r--r--overlays/elinks/default.nix14
-rw-r--r--overlays/elinks/elinks.json15
-rw-r--r--overlays/gitolite/default.nix8
-rwxr-xr-xoverlays/gitolite/invite172
-rw-r--r--overlays/gitweb/default.nix7
-rw-r--r--overlays/gitweb/theme/git-favicon.pngbin1125 -> 0 bytes
-rw-r--r--overlays/gitweb/theme/git-logo.pngbin2412 -> 0 bytes
-rw-r--r--overlays/gitweb/theme/gitweb.css783
-rw-r--r--overlays/gitweb/theme/gitweb.js27
-rw-r--r--overlays/goaccess/default.nix13
-rw-r--r--overlays/kanboard/default.nix18
-rw-r--r--overlays/khal/default.nix8
-rw-r--r--overlays/ledger/default.nix20
-rw-r--r--overlays/lesspipe/default.nix5
-rw-r--r--overlays/morph/default.nix5
-rw-r--r--overlays/morph/dry-run.patch59
-rw-r--r--overlays/morph/verbose_nix.patch12
-rw-r--r--overlays/neomutt/default.nix7
-rw-r--r--overlays/neomutt/tx.patch44
-rw-r--r--overlays/nix-direnv/default.nix7
-rw-r--r--overlays/nixops/default.nix20
-rw-r--r--overlays/nixops/fix_glibc.patch15
-rw-r--r--overlays/nixops/hetzner_cloud.patch480
-rw-r--r--overlays/pass/default.nix5
-rw-r--r--overlays/pass/pass-fix-pass-init.patch42
-rw-r--r--overlays/pelican/default.nix7
-rw-r--r--overlays/php-packages/default.nix6
-rw-r--r--overlays/php-packages/mysqli_patch.patch11
-rw-r--r--overlays/postfix/default.nix3
-rw-r--r--overlays/procps-ng/default.nix5
-rw-r--r--overlays/python-packages/buildbot.nix8
-rw-r--r--overlays/python-packages/default.nix29
-rw-r--r--overlays/sc-im/default.nix9
-rw-r--r--overlays/shaarli/default.nix15
-rw-r--r--overlays/shaarli/shaarli_ldap.patch425
-rw-r--r--overlays/slrn/default.nix5
-rw-r--r--overlays/taskwarrior/TW-1778_patch.diff12
-rw-r--r--overlays/taskwarrior/default.nix16
-rw-r--r--overlays/vcsh/default.nix7
-rw-r--r--overlays/weechat/default.nix12
-rw-r--r--overlays/ympd/default.nix5
-rw-r--r--overlays/ympd/ympd-password-env.patch23
-rw-r--r--overlays/ympd/ympd.json15
56 files changed, 0 insertions, 3094 deletions
diff --git a/overlays/bitlbee-discord/default.nix b/overlays/bitlbee-discord/default.nix
deleted file mode 100644
index bf8e5db..0000000
--- a/overlays/bitlbee-discord/default.nix
+++ /dev/null
@@ -1,12 +0,0 @@
1self: super: {
2 bitlbee-discord = super.bitlbee-discord.overrideAttrs(old: rec {
3 version = "master-3061edd";
4 name = "bitlbee-discord-${version}";
5 src = self.fetchFromGitHub {
6 rev = "master";
7 owner = "sm00th";
8 repo = "bitlbee-discord";
9 sha256 = "07gjd4b0g09888gpaqwcjafr8m292y2qz0gzharxjh1k2jbs88g3";
10 };
11 });
12}
diff --git a/overlays/bitlbee/bitlbee_long_nicks.patch b/overlays/bitlbee/bitlbee_long_nicks.patch
deleted file mode 100644
index 70be092..0000000
--- a/overlays/bitlbee/bitlbee_long_nicks.patch
+++ /dev/null
@@ -1,56 +0,0 @@
1diff --git a/bitlbee.h b/bitlbee.h
2index 17ab2979..5858277e 100644
3--- a/bitlbee.h
4+++ b/bitlbee.h
5@@ -121,7 +121,7 @@ extern "C" {
6 #define CONTROL_TOPIC "Welcome to the control channel. Type \2help\2 for help information."
7 #define IRCD_INFO PACKAGE " <http://www.bitlbee.org/>"
8
9-#define MAX_NICK_LENGTH 24
10+#define MAX_NICK_LENGTH 99
11
12 #define HELP_FILE VARDIR "help.txt"
13 #define CONF_FILE_DEF ETCDIR "bitlbee.conf"
14diff --git a/tests/check_nick.c b/tests/check_nick.c
15index ca5e5111..909fdcc9 100644
16--- a/tests/check_nick.c
17+++ b/tests/check_nick.c
18@@ -11,16 +11,16 @@
19 START_TEST(test_nick_strip){
20 int i;
21 const char *get[] = { "test:", "test", "test\n",
22- "thisisaveryveryveryverylongnick",
23- "thisisave:ryveryveryverylongnick",
24+ "thisisaveryveryveryveryveryveryverylongnickthisisaveryveryveryveryveryveryverylongnickthisisaveryveryveryveryveryveryverylongnick",
25+ "thisis:averyveryveryveryveryveryverylongnickthisisaveryveryveryveryveryveryverylongnickthisisaveryveryveryveryveryveryverylongnick",
26 "t::::est",
27 "test123",
28 "123test",
29 "123",
30 NULL };
31 const char *expected[] = { "test", "test", "test",
32- "thisisaveryveryveryveryl",
33- "thisisaveryveryveryveryl",
34+ "thisisaveryveryveryveryveryveryverylongnickthisisaveryveryveryveryveryveryverylongnickthisisaveryve",
35+ "thisisaveryveryveryveryveryveryverylongnickthisisaveryveryveryveryveryveryverylongnickthisisaveryve",
36 "test",
37 "test123",
38 "_123test",
39@@ -28,7 +28,7 @@ START_TEST(test_nick_strip){
40 NULL };
41
42 for (i = 0; get[i]; i++) {
43- char copy[60];
44+ char copy[260];
45 strcpy(copy, get[i]);
46 nick_strip(NULL, copy);
47 fail_unless(strcmp(copy, expected[i]) == 0,
48@@ -53,7 +53,7 @@ END_TEST
49
50 START_TEST(test_nick_ok_notok)
51 {
52- const char *nicks[] = { "thisisaveryveryveryveryveryveryverylongnick",
53+ const char *nicks[] = { "thisisaveryveryveryveryveryveryverylongnickthisisaveryveryveryveryveryveryverylongnickthisisaveryveryveryveryveryveryverylongnick",
54 "\nillegalchar", "", "nick%", "123test", NULL };
55 int i;
56
diff --git a/overlays/bitlbee/default.nix b/overlays/bitlbee/default.nix
deleted file mode 100644
index 5183d01..0000000
--- a/overlays/bitlbee/default.nix
+++ /dev/null
@@ -1,5 +0,0 @@
1self: super: {
2 bitlbee = super.bitlbee.overrideAttrs(old: {
3 patches = (old.patches or []) ++ [ ./bitlbee_long_nicks.patch ];
4 });
5}
diff --git a/overlays/bonfire/default.nix b/overlays/bonfire/default.nix
deleted file mode 100644
index 6dc1034..0000000
--- a/overlays/bonfire/default.nix
+++ /dev/null
@@ -1,36 +0,0 @@
1self: super: {
2 bonfire = let
3 click = self.python3Packages.click.overridePythonAttrs(old: rec {
4 version = "6.7";
5 src = self.python3Packages.fetchPypi {
6 pname = "click";
7 inherit version;
8 sha256 = "02qkfpykbq35id8glfgwc38yc430427yd05z1wc5cnld8zgicmgi";
9 };
10 postPatch = ''
11 substituteInPlace click/_unicodefun.py --replace "'locale'" "'${self.locale}/bin/locale'"
12 '';
13 doCheck = false;
14 });
15 keyring = self.python3Packages.keyring.overridePythonAttrs(old: rec {
16 version = "20.0.1";
17 src = self.python3Packages.fetchPypi {
18 pname = "keyring";
19 inherit version;
20 sha256 = "963bfa7f090269d30bdc5e25589e5fd9dad2cf2a7c6f176a7f2386910e5d0d8d";
21 };
22 });
23 in
24 super.bonfire.overridePythonAttrs(old: {
25 version = "0.0.8";
26 src = self.fetchFromGitHub {
27 owner = "blue-yonder";
28 repo = "bonfire";
29 rev = "0a0f18469d484aba6871fa7421bbb2c00ccefcb0";
30 sha256 = "1y2r537ibghhmk6jngw0zwvh1vn2bihqcvji50ffh1j0qc6q3x6x";
31 };
32 postPatch = "";
33 propagatedBuildInputs = self.lib.subtractLists [ self.python3Packages.click self.python3Packages.keyring ] old.propagatedBuildInputs ++ [ click keyring ];
34 meta.broken = false;
35 });
36}
diff --git a/overlays/bugwarrior/default.nix b/overlays/bugwarrior/default.nix
deleted file mode 100644
index 2b25985..0000000
--- a/overlays/bugwarrior/default.nix
+++ /dev/null
@@ -1,5 +0,0 @@
1self: super: {
2 bugwarrior = super.python3Packages.bugwarrior.overridePythonAttrs(old: rec {
3 patches = old.patches or [] ++ [ ./mantisbt.patch ];
4 });
5}
diff --git a/overlays/bugwarrior/mantisbt.patch b/overlays/bugwarrior/mantisbt.patch
deleted file mode 100644
index 85e5af1..0000000
--- a/overlays/bugwarrior/mantisbt.patch
+++ /dev/null
@@ -1,379 +0,0 @@
1diff --git a/bugwarrior/services/mantisbt.py b/bugwarrior/services/mantisbt.py
2new file mode 100644
3index 0000000..e54af0d
4--- /dev/null
5+++ b/bugwarrior/services/mantisbt.py
6@@ -0,0 +1,361 @@
7+from builtins import filter
8+import re
9+import six
10+
11+import requests
12+from jinja2 import Template
13+
14+from bugwarrior.config import asbool, aslist, die
15+from bugwarrior.services import IssueService, Issue, ServiceClient
16+
17+import logging
18+log = logging.getLogger(__name__)
19+
20+
21+class MantisbtClient(ServiceClient):
22+ def __init__(self, host, token):
23+ self.host = host
24+ self.session = requests.Session()
25+ self.session.headers['Authorization'] = token
26+
27+ def _api_url(self, path, **context):
28+ """ Build the full url to the API endpoint """
29+ baseurl = "https://{}/api/rest".format(self.host)
30+ return baseurl + path.format(**context)
31+
32+ def get_user(self):
33+ return self.json_response(self.session.get(self._api_url("/users/me")))
34+
35+ def get_projects(self):
36+ return self._getter(self._api_url("/projects"), subkey="projects")
37+
38+ def get_issues(self):
39+ url = self._api_url("/issues?page_size=50")
40+ return self._getter(url, page_size=50, subkey="issues")
41+
42+ def get_assigned_issues(self):
43+ """ Returns all issues assigned to authenticated user.
44+ """
45+ url = self._api_url("/issues?page_size=50&filter_id=assigned")
46+ return self._getter(url, page_size=50, subkey="issues")
47+
48+ def get_monitored_issues(self):
49+ """ Returns all issues monitored by authenticated user.
50+ """
51+ url = self._api_url("/issues?page_size=50&filter_id=monitored")
52+ return self._getter(url, page_size=50, subkey="issues")
53+
54+ def get_reported_issues(self):
55+ """ Returns all issues reported by authenticated user.
56+ """
57+ url = self._api_url("/issues?page_size=50&filter_id=reported")
58+ return self._getter(url, page_size=50, subkey="issues")
59+
60+ def _getter(self, url, page_size=None, subkey=None):
61+ """ Pagination utility. Obnoxious. """
62+
63+ results = []
64+ link = dict(next=url)
65+ page_number = 1
66+
67+ while 'next' in link:
68+ if page_size is not None:
69+ response = self.session.get(link['next'] + "&page=" + str(page_number))
70+ else:
71+ response = self.session.get(link['next'])
72+
73+ json_res = self.json_response(response)
74+
75+ if subkey is not None:
76+ json_res = json_res[subkey]
77+
78+ results += json_res
79+
80+ if page_size is not None and len(json_res) == page_size:
81+ page_number += 1
82+ else:
83+ break
84+
85+ return results
86+
87+class MantisbtIssue(Issue):
88+ TITLE = 'mantisbttitle'
89+ BODY = 'mantisbtbody'
90+ CREATED_AT = 'mantisbtcreatedon'
91+ UPDATED_AT = 'mantisbtupdatedat'
92+ CLOSED_AT = 'mantisbtclosedon'
93+ URL = 'mantisbturl'
94+ PROJECT = 'mantisbtproject'
95+ NUMBER = 'mantisbtnumber'
96+ USER = 'mantisbtuser'
97+ CATEGORY = 'mantisbtcategory'
98+ STATE = 'mantisbtstate'
99+
100+ UDAS = {
101+ TITLE: {
102+ 'type': 'string',
103+ 'label': 'Mantisbt Title',
104+ },
105+ BODY: {
106+ 'type': 'string',
107+ 'label': 'Mantisbt Body',
108+ },
109+ CREATED_AT: {
110+ 'type': 'date',
111+ 'label': 'Mantisbt Created',
112+ },
113+ UPDATED_AT: {
114+ 'type': 'date',
115+ 'label': 'Mantisbt Updated',
116+ },
117+ CLOSED_AT: {
118+ 'type': 'date',
119+ 'label': 'Mantisbt Closed',
120+ },
121+ PROJECT: {
122+ 'type': 'string',
123+ 'label': 'Mantisbt Project',
124+ },
125+ URL: {
126+ 'type': 'string',
127+ 'label': 'Mantisbt URL',
128+ },
129+ NUMBER: {
130+ 'type': 'numeric',
131+ 'label': 'Mantisbt Issue #',
132+ },
133+ USER: {
134+ 'type': 'string',
135+ 'label': 'Mantisbt User',
136+ },
137+ CATEGORY: {
138+ 'type': 'string',
139+ 'label': 'Mantisbt Category',
140+ },
141+ STATE: {
142+ 'type': 'string',
143+ 'label': 'Mantisbt State',
144+ }
145+ }
146+ UNIQUE_KEY = (URL, NUMBER, )
147+
148+ def _normalize_tag(self, label):
149+ return re.sub(r'[^a-zA-Z0-9]', '_', label)
150+
151+ def to_taskwarrior(self):
152+ body = self.record.get('description')
153+ if body:
154+ body = body.replace('\r\n', '\n')
155+
156+ created = self.parse_date(self.record.get('created_at'))
157+ updated = self.parse_date(self.record.get('updated_at'))
158+ closed_date = None
159+ if self.record["status"]["name"] in ["closed", "resolved"]:
160+ for history in self.record.get("history", []):
161+ if history.get("field", {}).get("name", "") == "status"\
162+ and history.get("new_value", {}).get("name", "") in ["closed", "resolved"]:
163+ closed_date = history["created_at"]
164+ closed = self.parse_date(closed_date)
165+
166+ return {
167+ 'project': self.record['project']['name'],
168+ 'priority': self.origin['default_priority'],
169+ 'annotations': self.get_annotations(),
170+ 'tags': self.get_tags(),
171+ 'entry': created,
172+ 'end': closed,
173+
174+ self.TITLE: self.record.get('summary'),
175+ self.BODY: body,
176+ self.CREATED_AT: created,
177+ self.UPDATED_AT: updated,
178+ self.CLOSED_AT: closed,
179+ self.URL: self.get_url(),
180+ self.PROJECT: self.record['project'].get('name'),
181+ self.NUMBER: self.record['id'],
182+ self.USER: self.record['reporter'].get('name'),
183+ self.CATEGORY: self.record['category'].get('name'),
184+ self.STATE: self.record['status'].get('label'),
185+ }
186+
187+ def get_url(self):
188+ return "https://{}view.php?id={}".format(self.extra['host'], self.record["id"])
189+
190+ def get_annotations(self):
191+ annotations = []
192+
193+ context = self.record.copy()
194+ annotation_template = Template(self.origin['annotation_template'])
195+
196+ for annotation_dict in self.record.get('notes', []):
197+ context.update({
198+ 'text': annotation_dict['text'],
199+ 'date': annotation_dict['created_at'],
200+ 'author': annotation_dict['reporter'].get('name', 'unknown'),
201+ 'view': annotation_dict['view_state']['label'],
202+ })
203+ annotations.append(
204+ annotation_template.render(context)
205+ )
206+ return annotations
207+
208+ def get_tags(self):
209+ tags = []
210+
211+ context = self.record.copy()
212+ tag_template = Template(self.origin['tag_template'])
213+
214+ for tag_dict in self.record.get('tags', []):
215+ context.update({
216+ 'tag': self._normalize_tag(tag_dict['name'])
217+ })
218+ tags.append(
219+ tag_template.render(context)
220+ )
221+
222+ return tags
223+
224+ def get_default_description(self):
225+ return self.build_default_description(
226+ title=self.record['summary'],
227+ url=self.get_processed_url(self.get_url()),
228+ number=self.record['id'],
229+ )
230+
231+
232+class MantisbtService(IssueService):
233+ ISSUE_CLASS = MantisbtIssue
234+ CONFIG_PREFIX = 'mantisbt'
235+
236+ def __init__(self, *args, **kw):
237+ super(MantisbtService, self).__init__(*args, **kw)
238+
239+ self.host = self.config.get('host', 'www.mantisbt.org/bugs/')
240+
241+ token = self.get_password('token')
242+
243+ self.client = MantisbtClient(self.host, token)
244+ self.user = None
245+
246+ self.exclude_projects = self.config.get('exclude_projects', [], aslist)
247+ self.include_projects = self.config.get('include_projects', [], aslist)
248+
249+ self.involved_issues = self.config.get(
250+ 'involved_issues', default=True, to_type=asbool
251+ )
252+ self.assigned_issues = self.config.get(
253+ 'assigned_issues', default=False, to_type=asbool
254+ )
255+ self.monitored_issues = self.config.get(
256+ 'monitored_issues', default=False, to_type=asbool
257+ )
258+ self.reported_issues = self.config.get(
259+ 'reported_issues', default=False, to_type=asbool
260+ )
261+ self.tag_template = self.config.get(
262+ 'tag_template', default='{{tag}}', to_type=six.text_type
263+ )
264+ self.annotation_template = self.config.get(
265+ 'annotation_template', default='{{date}} {{author}} ({{view}}): {{text}}', to_type=six.text_type
266+ )
267+
268+ def get_service_metadata(self):
269+ return {
270+ 'tag_template': self.tag_template,
271+ 'annotation_template': self.annotation_template,
272+ }
273+
274+ def filter_involved_issues(self, issue):
275+ _, issue = issue
276+ user = self.client.get_user()
277+ uid = user["id"]
278+ if issue["reporter"]["id"] != uid and \
279+ issue.get("handler", {}).get("id") != uid and \
280+ all([ x.get("user", {}).get("id") != uid for x in issue.get("history", [])]) and \
281+ all([ x.get("user", {}).get("id") != uid for x in issue.get("monitors", [])]):
282+ return False
283+ return self.filter_project_name(issue["project"]["name"])
284+
285+ def filter_issues(self, issue):
286+ _, issue = issue
287+ return self.filter_project_name(issue["project"]["name"])
288+
289+ def filter_project_name(self, name):
290+ if self.exclude_projects:
291+ if name in self.exclude_projects:
292+ return False
293+
294+ if self.include_projects:
295+ if name in self.include_projects:
296+ return True
297+ else:
298+ return False
299+
300+ return True
301+
302+ @staticmethod
303+ def get_keyring_service(service_config):
304+ host = service_config.get('host', 'www.mantisbt.org/bugs/')
305+ username = service_config.get('username', default='nousername')
306+ return "mantisbt://{username}@{host}".format(username=username,
307+ host=host)
308+
309+ @staticmethod
310+ def to_issue_dict(issues):
311+ return { i['id']: i for i in issues }
312+
313+ def get_owner(self, issue):
314+ return issue.get("handler", {}).get("name")
315+
316+ def get_author(self, issue):
317+ return issue.get("reporter", {}).get("name")
318+
319+ def issues(self):
320+ issues = {}
321+ is_limited = self.assigned_issues or self.monitored_issues or self.reported_issues
322+
323+ if self.assigned_issues:
324+ issues.update(
325+ filter(self.filter_issues, self.to_issue_dict(self.client.get_assigned_issues()).items())
326+ )
327+ if self.monitored_issues:
328+ issues.update(
329+ filter(self.filter_issues, self.to_issue_dict(self.client.get_monitored_issues()).items())
330+ )
331+ if self.reported_issues:
332+ issues.update(
333+ filter(self.filter_issues, self.to_issue_dict(self.client.get_reported_issues()).items())
334+ )
335+
336+ if not is_limited:
337+ all_issues = self.to_issue_dict(self.client.get_issues())
338+ if self.involved_issues:
339+ issues.update(
340+ filter(self.filter_involved_issues, all_issues.items())
341+ )
342+ else:
343+ issues.update(
344+ filter(self.filter_issues, all_issues.items())
345+ )
346+
347+ log.debug(" Found %i issues.", len(issues))
348+ if not is_limited:
349+ issues = list(filter(self.include, issues.values()))
350+ else:
351+ issues = list(issues.values())
352+ log.debug(" Pruned down to %i issues.", len(issues))
353+
354+ for issue in issues:
355+ issue_obj = self.get_issue_for_record(issue)
356+ extra = {
357+ 'host': self.host
358+ }
359+ issue_obj.update_extra(extra)
360+ yield issue_obj
361+
362+ @classmethod
363+ def validate_config(cls, service_config, target):
364+ if 'token' not in service_config:
365+ die("[%s] has no 'mantisbt.token'" % target)
366+
367+ super(MantisbtService, cls).validate_config(service_config, target)
368diff --git a/setup.py b/setup.py
369index d6d957a..665e36e 100644
370--- a/setup.py
371+++ b/setup.py
372@@ -80,6 +80,7 @@ setup(name='bugwarrior',
373 activecollab2=bugwarrior.services.activecollab2:ActiveCollab2Service
374 activecollab=bugwarrior.services.activecollab:ActiveCollabService
375 jira=bugwarrior.services.jira:JiraService
376+ mantisbt=bugwarrior.services.mantisbt:MantisbtService
377 megaplan=bugwarrior.services.megaplan:MegaplanService
378 phabricator=bugwarrior.services.phab:PhabricatorService
379 versionone=bugwarrior.services.versionone:VersionOneService
diff --git a/overlays/bundix/default.nix b/overlays/bundix/default.nix
deleted file mode 100644
index 6c4046c..0000000
--- a/overlays/bundix/default.nix
+++ /dev/null
@@ -1,7 +0,0 @@
1self: super: {
2 bundix = super.bundix.overrideAttrs (old: {
3 preBuild = (old.preBuild or "") + ''
4 sed -i -e "/case obj/a\ when nil\n nil" lib/bundix/nixer.rb
5 '';
6 });
7}
diff --git a/overlays/databases/mysql/default.nix b/overlays/databases/mysql/default.nix
deleted file mode 100644
index f9e5791..0000000
--- a/overlays/databases/mysql/default.nix
+++ /dev/null
@@ -1,24 +0,0 @@
1self: super: rec {
2 mariadb_pam = super.mariadb.overrideAttrs(old: {
3 cmakeFlags = old.cmakeFlags ++ [ "-DWITH_AUTHENTICATION_PAM=ON" ];
4 buildInputs = old.buildInputs ++ [ self.pam ];
5 outputs = old.outputs ++ [ "dev" ];
6 postInstall = ''
7 mkdir -p $dev $dev/lib $dev/share
8 cp -a $out/include $dev
9 cp -a $out/lib/{libmariadbclient.a,libmysqlclient.a,libmysqlclient_r.a,libmysqlservices.a} $dev/lib
10 cp -a $out/lib/pkgconfig $dev/lib
11 cp -a $out/share/aclocal $dev/share
12 '' + old.postInstall;
13 });
14 # This patched version includes C headers from the server part (see
15 # above). It seems to be required to build pam support in clients.
16 libmysqlclient_pam = super.libmysqlclient.overrideAttrs(old: {
17 prePatch = old.prePatch or "" + ''
18 sed -i -e '/define INCLUDE/s|"$| -I@CMAKE_SYSROOT@@CMAKE_INSTALL_PREFIX@/@INSTALL_INCLUDEDIR@/mysql/server -I@CMAKE_SYSROOT@@CMAKE_INSTALL_PREFIX@/@INSTALL_INCLUDEDIR@/mysql/server/private"|' mariadb_config/mariadb_config.c.in
19 '';
20 postInstall = old.postInstall or "" + ''
21 cp -a ${mariadb_pam.dev}/include/* $out/include/mariadb
22 '';
23 });
24}
diff --git a/overlays/databases/postgresql/default.nix b/overlays/databases/postgresql/default.nix
deleted file mode 100644
index 9ada29c..0000000
--- a/overlays/databases/postgresql/default.nix
+++ /dev/null
@@ -1,8 +0,0 @@
1self: super: rec {
2 postgresql_pam = super.postgresql_11.overrideAttrs(old: {
3 # datadir in /var/lib/postgresql is named after psqlSchema
4 passthru = old.passthru // { psqlSchema = "11.0"; };
5 configureFlags = old.configureFlags ++ [ "--with-pam" ];
6 buildInputs = (old.buildInputs or []) ++ [ self.pam ];
7 });
8}
diff --git a/overlays/default.nix b/overlays/default.nix
deleted file mode 100644
index bdc99d2..0000000
--- a/overlays/default.nix
+++ /dev/null
@@ -1,48 +0,0 @@
1let
2 flakeCompat = import ../lib/flake-compat.nix;
3 flakes = builtins.foldl' (a: b: a // b) {} (map (n: (flakeCompat n).overlays) [
4 ../flakes/backports
5 ../flakes/openarc
6 ../flakes/opendmarc
7 ../flakes/peertube
8 ../flakes/private/peertube
9 ]);
10in flakes // {
11 mylibs = self: super: { mylibs = import ../lib { pkgs = self; }; };
12 mypkgs = self: super: import ../pkgs { pkgs = self; };
13
14 bitlbee = import ./bitlbee;
15 bitlbee-discord = import ./bitlbee-discord;
16 bonfire = import ./bonfire;
17 bundix = import ./bundix;
18 bugwarrior = import ./bugwarrior;
19 dwm = import ./dwm;
20 elinks = import ./elinks;
21 gitweb = import ./gitweb;
22 gitolite = import ./gitolite;
23 goaccess = import ./goaccess;
24 kanboard = import ./kanboard;
25 ledger = import ./ledger;
26 lesspipe = import ./lesspipe;
27 mysql = import ./databases/mysql;
28 neomutt = import ./neomutt;
29 nixops = import ./nixops;
30 pass = import ./pass;
31 pelican = import ./pelican;
32 php-packages = import ./php-packages;
33 postfix = import ./postfix;
34 postgresql = import ./databases/postgresql;
35 procps-ng = import ./procps-ng;
36 sc-im = import ./sc-im;
37 shaarli = import ./shaarli;
38 slrn = import ./slrn;
39 taskwarrior = import ./taskwarrior;
40 vcsh = import ./vcsh;
41 weechat = import ./weechat;
42 ympd = import ./ympd;
43 doing = import ./doing;
44 khal = import ./khal;
45 nix-direnv = import ./nix-direnv;
46 morph = import ./morph;
47}
48// import ./python-packages
diff --git a/overlays/doing/default.nix b/overlays/doing/default.nix
deleted file mode 100644
index 7f95fb6..0000000
--- a/overlays/doing/default.nix
+++ /dev/null
@@ -1,10 +0,0 @@
1self: super: {
2 defaultGemConfig = super.defaultGemConfig // {
3 doing = attrs: {
4 postInstall = ''
5 installPath=$(cat $out/nix-support/gem-meta/install-path)
6 sed -i $installPath/lib/doing/wwid.rb -e "/Create a backup copy for the undo command/ {n;d}"
7 '';
8 };
9 };
10}
diff --git a/overlays/dwm/default.nix b/overlays/dwm/default.nix
deleted file mode 100644
index 96ed3ff..0000000
--- a/overlays/dwm/default.nix
+++ /dev/null
@@ -1,7 +0,0 @@
1self: super: {
2 dwm = super.dwm.overrideAttrs(old: rec {
3 postPatch = ''
4 cp ${./dwm_config.h} ./config.h
5 '';
6 });
7}
diff --git a/overlays/dwm/dwm_config.h b/overlays/dwm/dwm_config.h
deleted file mode 100644
index b1587e8..0000000
--- a/overlays/dwm/dwm_config.h
+++ /dev/null
@@ -1,98 +0,0 @@
1/* See LICENSE file for copyright and license details. */
2
3/* appearance */
4static const unsigned int borderpx = 1; /* border pixel of windows */
5static const unsigned int snap = 32; /* snap pixel */
6static const int showbar = 1; /* 0 means no bar */
7static const int topbar = 1; /* 0 means bottom bar */
8static const char *fonts[] = { "monospace:size=10" };
9static const char dmenufont[] = "monospace:size=10";
10static const char col_gray1[] = "#222222";
11static const char col_gray2[] = "#444444";
12static const char col_gray3[] = "#bbbbbb";
13static const char col_gray4[] = "#eeeeee";
14static const char col_cyan[] = "#005577";
15static const char *colors[][3] = {
16 /* fg bg border */
17 [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
18 [SchemeSel] = { col_gray4, col_cyan, col_cyan },
19};
20
21/* tagging */
22static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
23
24static const Rule rules[] = {
25 /* xprop(1):
26 * WM_CLASS(STRING) = instance, class
27 * WM_NAME(STRING) = title
28 */
29 /* class instance title tags mask isfloating monitor */
30 { "Nextcloud", NULL, NULL, 9 << 8, 0, -1 },
31};
32
33/* layout(s) */
34static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
35static const int nmaster = 1; /* number of clients in master area */
36static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
37
38static const Layout layouts[] = {
39 /* symbol arrange function */
40 { "[M]", monocle }, /* first entry is default */
41 { "[]=", tile },
42 { "><>", NULL }, /* no layout function means floating behavior */
43};
44
45/* key definitions */
46#define MODKEY Mod1Mask
47#define TAGKEYS(KEY,TAG) \
48 { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
49 { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
50 { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
51 { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
52
53/* helper for spawning shell commands in the pre dwm-5.0 fashion */
54#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
55
56/* commands */
57static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
58static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
59static const char *termcmd[] = { "st", NULL };
60
61static Key keys[] = {
62 /* modifier key function argument */
63 { MODKEY, XK_p, spawn, {.v = dmenucmd } },
64 { MODKEY, XK_t, spawn, {.v = termcmd } },
65 { MODKEY, XK_Tab, view, {0} },
66 { MODKEY|ShiftMask, XK_c, killclient, {0} },
67 { MODKEY, XK_j, focusstack, {.i = +1 } },
68 { MODKEY, XK_k, focusstack, {.i = -1 } },
69 { MODKEY, XK_Return, zoom, {0} },
70 TAGKEYS( XK_1, 0)
71 TAGKEYS( XK_2, 1)
72 TAGKEYS( XK_3, 2)
73 TAGKEYS( XK_4, 3)
74 TAGKEYS( XK_5, 4)
75 TAGKEYS( XK_6, 5)
76 TAGKEYS( XK_7, 6)
77 TAGKEYS( XK_8, 7)
78 TAGKEYS( XK_9, 8)
79 { MODKEY|ShiftMask, XK_q, quit, {0} },
80};
81
82/* button definitions */
83/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
84static Button buttons[] = {
85 /* click event mask button function argument */
86 { ClkLtSymbol, 0, Button1, setlayout, {0} },
87 { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
88 { ClkWinTitle, 0, Button2, zoom, {0} },
89 { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
90 { ClkClientWin, MODKEY, Button1, movemouse, {0} },
91 { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
92 { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
93 { ClkTagBar, 0, Button1, view, {0} },
94 { ClkTagBar, 0, Button3, toggleview, {0} },
95 { ClkTagBar, MODKEY, Button1, tag, {0} },
96 { ClkTagBar, MODKEY, Button3, toggletag, {0} },
97};
98
diff --git a/overlays/elinks/default.nix b/overlays/elinks/default.nix
deleted file mode 100644
index 1744dc0..0000000
--- a/overlays/elinks/default.nix
+++ /dev/null
@@ -1,14 +0,0 @@
1self: super: {
2 elinks = super.elinks.overrideAttrs (old:
3 self.mylibs.fetchedGithub ./elinks.json // rec {
4 preConfigure = ''sh autogen.sh'';
5 buildInputs = old.buildInputs ++ (with self; [ gettext automake autoconf ]);
6 configureFlags = [
7 "--disable-smb" "--without-x" "--enable-cgi"
8 "--enable-leds" "--enable-256-colors"
9 "--enable-html-highlight" "--with-zlib"
10 ];
11 patches = [];
12 }
13 );
14}
diff --git a/overlays/elinks/elinks.json b/overlays/elinks/elinks.json
deleted file mode 100644
index ea13b1f..0000000
--- a/overlays/elinks/elinks.json
+++ /dev/null
@@ -1,15 +0,0 @@
1{
2 "tag": "f86be65-master",
3 "meta": {
4 "name": "elinks",
5 "url": "https://github.com/nabetaro/elinks",
6 "branch": "master"
7 },
8 "github": {
9 "owner": "nabetaro",
10 "repo": "elinks",
11 "rev": "f86be659718c0cd0a67f88b42f07044c23d0d028",
12 "sha256": "1jxb7xgawcjkb3gw4gqyw26g02709wwdbhyczfckh3l4njxhy14m",
13 "fetchSubmodules": true
14 }
15}
diff --git a/overlays/gitolite/default.nix b/overlays/gitolite/default.nix
deleted file mode 100644
index 7f8f007..0000000
--- a/overlays/gitolite/default.nix
+++ /dev/null
@@ -1,8 +0,0 @@
1self: super: {
2 gitolite = super.gitolite.overrideAttrs(old: {
3 postPatch = old.postPatch + ''
4 sed -i -e "s@/bin/rm@rm@" src/commands/sskm
5 cp ${./invite} src/commands/invite
6 '';
7 });
8}
diff --git a/overlays/gitolite/invite b/overlays/gitolite/invite
deleted file mode 100755
index 3cc2dbd..0000000
--- a/overlays/gitolite/invite
+++ /dev/null
@@ -1,172 +0,0 @@
1#!/usr/bin/perl
2use strict;
3use warnings;
4
5use lib $ENV{GL_LIBDIR};
6use Gitolite::Rc;
7use Gitolite::Common;
8
9=for usage
10Please see usage at https://www.immae.eu/docs/forge-logicielle/gitolite.html#inviter-des-collaborateurs
11=cut
12
13usage() if @ARGV and ($ARGV[0] eq '-h' or $ARGV[0] eq '--help');
14
15my $rb = $rc{GL_REPO_BASE};
16my $ab = $rc{GL_ADMIN_BASE};
17# get to the keydir
18_chdir("$ab/keydir");
19
20# save arguments for later
21my $operation = shift || 'list';
22my $invitekeyid = shift || '';
23$invitekeyid and $invitekeyid !~ /^[-0-9a-z_]+@[-0-9a-z_]+$/i and die "invalid keyid $invitekeyid\n";
24my ($invited, $keyid) = split /@/, $invitekeyid;
25
26# get the actual userid and keytype
27my $gl_user = $ENV{GL_USER};
28die "This function is reserved for actual users" if $gl_user =~ s/-invite-(.*)$//;
29
30# ----
31# first collect the keys
32
33my ( @invited_keys );
34
35for my $pubkey (`find . -type f -name "*.pub" | sort`) {
36 chomp($pubkey);
37 $pubkey =~ s(^./)(); # artifact of the find command
38
39 my $user = $pubkey;
40 $user =~ s(.*/)(); # foo/bar/baz.pub -> baz.pub
41 $user =~ s/(\@[^.]+)?\.pub$//; # baz.pub, baz@home.pub -> baz
42
43 if ( $user =~ m(^(zzz-marked-for-...-)?$gl_user-invite-) ) {
44 push @invited_keys, $pubkey;
45 }
46}
47
48# ----
49# list mode; just do it and exit
50sub print_keylist {
51 my ( $message, @list ) = @_;
52 return unless @list;
53 print "== $message ==\n";
54 my $count = 1;
55 for (@list) {
56 my $fp = fingerprint($_);
57 s/(zzz-marked-for-...-)?$gl_user-invite-//g;
58 s/\.pub$//;
59 s(.*/)();
60 print $count++ . ": $fp : $_\n";
61 }
62}
63if ( $operation eq 'list' ) {
64 print "you have the following invited keys:\n";
65 print_keylist( "keys for invited persons", @invited_keys );
66 print "\n\n";
67 exit;
68}
69
70# ----
71# please see docs for details on how a user interacts with this
72
73die "valid operations: add, del\n" unless $operation =~ /^(add|del)$/;
74
75if ( $operation eq 'add' ) {
76 print STDERR "please supply the new key on STDIN. (I recommend you
77 don't try to do this interactively, but use a pipe)\n";
78 kf_add( $gl_user, $invited, $keyid, safe_stdin() );
79} elsif ( $operation eq 'del' ) {
80 kf_del( $gl_user, $invited, $keyid );
81}
82
83exit;
84
85# ----
86
87# make a temp clone and switch to it
88our $TEMPDIR;
89BEGIN { $TEMPDIR = `mktemp -d -t tmp.XXXXXXXXXX`; }
90END { `rm -rf $TEMPDIR`; }
91
92sub cd_temp_clone {
93 chomp($TEMPDIR);
94 hushed_git( "clone", "$rb/gitolite-admin.git", "$TEMPDIR" );
95 chdir($TEMPDIR);
96 my $hostname = `hostname`; chomp($hostname);
97 hushed_git( "config", "--get", "user.email" ) and hushed_git( "config", "user.email", $ENV{USER} . "@" . $hostname );
98 hushed_git( "config", "--get", "user.name" ) and hushed_git( "config", "user.name", "$ENV{USER} on $hostname" );
99}
100
101sub fingerprint {
102 my ($fp, $output) = ssh_fingerprint_file(shift);
103 # Do not print the output of $output to an untrusted destination.
104 die "does not seem to be a valid pubkey\n" unless $fp;
105 return $fp;
106}
107
108sub safe_stdin {
109 # read one line from STDIN
110 my $data;
111 my $ret = read STDIN, $data, 4096;
112 # current pubkeys are approx 400 bytes so we go a little overboard
113 die "could not read pubkey data" . ( defined($ret) ? "" : ": $!" ) . "\n" unless $ret;
114 die "pubkey data seems to have more than one line\n" if $data =~ /\n./;
115 return $data;
116}
117
118sub hushed_git {
119 local (*STDOUT) = \*STDOUT;
120 local (*STDERR) = \*STDERR;
121 open( STDOUT, ">", "/dev/null" );
122 open( STDERR, ">", "/dev/null" );
123 system( "git", @_ );
124}
125
126sub highlander {
127 # there can be only one
128 my ( $keyid, $die_if_empty, @a ) = @_;
129 # too many?
130 if ( @a > 1 ) {
131 print STDERR "
132more than one key satisfies this condition, and I can't deal with that!
133The keys are:
134
135";
136 print STDERR "\t" . join( "\n\t", @a ), "\n\n";
137 exit 1;
138 }
139 # too few?
140 die "no keys with " . ( $keyid || "empty" ) . " keyid found\n" if $die_if_empty and not @a;
141
142 return @a;
143}
144
145sub kf_add {
146 my ( $gl_user, $invited, $keyid, $keymaterial ) = @_;
147
148 # add a new "invited" key for $gl_user.
149 cd_temp_clone();
150 chdir("keydir");
151
152 mkdir("invited");
153 _print( "invited/$gl_user-invite-$invited\@$keyid.pub", $keymaterial );
154 hushed_git( "add", "." ) and die "git add failed\n";
155 my $fp = fingerprint("invited/$gl_user-invite-$invited\@$keyid.pub");
156 hushed_git( "commit", "-m", "invite add $gl_user-invite-$invited\@$keyid ($fp)" ) and die "git commit failed\n";
157 system("gitolite push >/dev/null 2>/dev/null") and die "git push failed\n";
158}
159
160sub kf_del {
161 my ( $gl_user, $invited, $keyid ) = @_;
162
163 cd_temp_clone();
164 chdir("keydir");
165
166 my @pk = highlander( $keyid, 1, grep { m(^(.*/)?(zzz-marked-for-...-)?$gl_user-invite-$invited\@$keyid.pub$) } @invited_keys );
167
168 my $fp = fingerprint( $pk[0] );
169 hushed_git( "rm", $pk[0]) and die "git mv failed\n";
170 hushed_git( "commit", "-m", "invite del $pk[0] ($fp)" ) and die "git commit failed\n";
171 system("gitolite push >/dev/null 2>/dev/null") and die "git push failed\n";
172}
diff --git a/overlays/gitweb/default.nix b/overlays/gitweb/default.nix
deleted file mode 100644
index 27a1152..0000000
--- a/overlays/gitweb/default.nix
+++ /dev/null
@@ -1,7 +0,0 @@
1self: super: {
2 gitweb = super.gitweb.overrideAttrs(old: {
3 postBuild = old.postBuild or "" + ''
4 cp -r ${./theme} $out/gitweb-theme;
5 '';
6 });
7}
diff --git a/overlays/gitweb/theme/git-favicon.png b/overlays/gitweb/theme/git-favicon.png
deleted file mode 100644
index 4fa44bb..0000000
--- a/overlays/gitweb/theme/git-favicon.png
+++ /dev/null
Binary files differ
diff --git a/overlays/gitweb/theme/git-logo.png b/overlays/gitweb/theme/git-logo.png
deleted file mode 100644
index fdaf7b7..0000000
--- a/overlays/gitweb/theme/git-logo.png
+++ /dev/null
Binary files differ
diff --git a/overlays/gitweb/theme/gitweb.css b/overlays/gitweb/theme/gitweb.css
deleted file mode 100644
index 83e0742..0000000
--- a/overlays/gitweb/theme/gitweb.css
+++ /dev/null
@@ -1,783 +0,0 @@
1/* Reset
2------------------------------------------------------------------------- */
3
4/* Based on http://meyerweb.com/eric/tools/css/reset/ */
5/* v1.0 | 20080212 */
6
7html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p,
8blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em,
9font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b,
10u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table,
11caption, tbody, tfoot, thead, tr, th, td {
12 margin: 0;
13 padding: 0;
14 border: 0;
15 outline: 0;
16 font-size: 100%;
17 vertical-align: baseline;
18 background: transparent;
19}
20
21ol, ul { list-style: none; }
22
23blockquote, q { quotes: none; }
24
25blockquote:before, blockquote:after,
26q:before, q:after {
27 content: '';
28 content: none;
29}
30
31:focus { outline: 0; }
32
33ins { text-decoration: none; }
34
35del { text-decoration: line-through; }
36
37table {
38 border-collapse: collapse;
39 border-spacing: 0;
40}
41
42a { outline: none; }
43
44/* General
45---------------------------------------------------------------------------- */
46
47html {
48 position: relative;
49 min-height: 100%;
50}
51
52body {
53 font: 13px Helvetica,arial,freesans,clean,sans-serif;
54 line-height: 1.4;
55 margin: 0 0 105px;
56 background-color: #fff;
57 color: #000000;
58}
59
60/* Monospaced Fonts */
61.sha1, .mode, .diff_tree .list, .pre, .diff, .patchset {
62 font-family: 'Consolas','Bitstream Vera Sans Mono',monospace;
63}
64
65a:link, a:visited {
66 color: #4183C4;
67 text-decoration: none;
68}
69
70a:hover {
71 text-decoration: underline;
72}
73
74td.list a[href*='tree'], td.list a[href*='blob'] {
75 padding-left: 20px;
76 display: block;
77 float: left;
78 height: 16px;
79 line-height: 16px;
80}
81
82td.list a[href*='tree'] {
83 background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABq0lEQVQ4y8WTu4oUQRSGv+rtGVuxhwVFdFEEE2c3d0HYTEMTn8DEVxADQTDUF9DMwMxQMBMx8AEWzRQ3cBHd9TI91+2urjq/QbczY2IygSep4nD+79yqnCRWsYQVbWVACvDh5ZXdrLe15dwyT1TjT/sxFFeB6i+VA2B6+cb7kAI4Jf0LO087zjlQI8Y5Qvnj0sHug321XoC1bk+K9eHk6+s7wPMUgKAS88eqb4+Jfg2SHs7lZBvX2Nh+2EUCDGSAcMnJsx9f7NxfAGqXyDzRd5EJO/pMPT1gcviGTnYOVIN5pAAE8v7dLrKL8xnglFk4ws9Afko9HpH3b5Gd2mwb/lOBmgrSdYhJugDUCenxM6xv3p4HCsP8F0LxCsUhCkMURihOyM7fg0osASTFEpu9a4LjGIUCqwcoDiEUrX+E4hRUQb20RiokC1j9vckUhygU7X3QZh7NAVKYL7YBeMkRUfjVCotF2XGIwnghtrJpMywB5G0QZj9P1JNujuWJ1AHLQadRrACPkuZ0SSSWpeStWgDK6tHek5vbiOs48n++XQHurcf0rFng//6NvwG+iB9/4duaTgAAAABJRU5ErkJgggo=) center left no-repeat;
84}
85
86td.list a[href*='blob'] {
87 background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAA6ElEQVQoFQXBMW5TQRgGwNnHnoE0QbiCjoIooUmTU3AuS1BwIoTSUdJBigg3GCWOg9/++zHTop078wIAsPMrE4SL5/1aIyMjIyMjz/m0tbFECFdrPeaQQw75mz/5nZH7fN7aWILmauSYfznmmIfss8vIUx7zZWsTTXM5vpWvTk5Wq9VHQP/gtgOLa0Qpw940vAQdaG6thpOhlOkG0AEuAVGmEkAH+G4YSikxXQM6wDsAMRFAB/ihDNNUmN4DOsAbBAEAdICfpmmaAt4COoj2GgCASbIkZh1NAACznhQt2itnFgAAlF3u/gMDtJXPzQxoswAAAABJRU5ErkJgggo=) center left no-repeat;
88}
89
90i {
91 font-style: normal;
92}
93
94td, th {
95 padding: 5px;
96}
97
98.page_nav br {
99 display: none;
100}
101
102/* Page Header
103---------------------------------------------------------------------------- */
104
105.page_header {
106 height: 50px;
107 line-height: 50px;
108 position: relative;
109 padding: 0 27px;
110 margin-bottom: 20px;
111 font-size: 20px;
112 font-family: Helvetica, Arial, Freesans, Clean, sans-serif;
113 background: #FFFFFF; /* old browsers */
114 background: -moz-linear-gradient(top, #FFFFFF 0%, #F5F5F5 100%); /* firefox */
115 background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#FFFFFF), color-stop(100%,#F5F5F5)); /* webkit */
116 filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#F5F5F5',GradientType=0 ); /* ie */
117 background: -o-linear-gradient(top, #FFFFFF 0%, #F5F5F5 100%);
118 border-bottom: 1px solid #dfdfdf;
119}
120
121.page_header a:link, .page_header a:visited {
122 color: #4183C4;
123 text-decoration: none;
124 padding: 3px;
125 font-weight: bold;
126}
127
128.page_header a:hover {
129 font-weight: bold;
130 padding: 3px;
131 text-decoration: underline;
132}
133
134.page_header a:first-child {
135 background: transparent;
136}
137
138.page_header img.logo {
139 position: relative;
140 top: 7px;
141 margin-right: 5px;
142}
143
144/* Page Footer
145---------------------------------------------------------------------------- */
146
147.page_footer {
148 position: absolute;
149 left: 0;
150 bottom: 0;
151 width: 100%;
152 height: 80px;
153 line-height: 80px;
154 margin-top: 15px;
155 background: #f1f1f1;
156 border-top: 2px solid #ddd;
157 border-bottom: 1px solid #ddd;
158}
159
160.page_footer_text {
161 color: #666;
162 display: inline;
163 float: left;
164 margin-left: 25px;
165 width: 80%;
166 overflow: hidden;
167 white-space: nowrap;
168 text-overflow: ellipsis;
169}
170
171a.rss_logo {
172 float: right;
173 padding: 3px 1px;
174 width: 35px;
175 line-height: 10px;
176 border: 1px solid;
177 border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e;
178 color: #ffffff;
179 background-color: #ff6600;
180 font-weight: bold;
181 font-family: sans-serif;
182 font-size: 80%;
183 text-align: center;
184 text-decoration: none;
185 margin-top: 30px;
186 margin-left: 5px;
187}
188
189a.rss_logo:hover {
190 background-color: #ee5500;
191}
192
193.rss_logo {
194 margin-right: 25px;
195 background: yellow;
196}
197
198.rss_logo:last-child {
199 margin-right: 5px;
200}
201
202/* Index include
203---------------------------------------------------------------------------- */
204
205.index_include {
206 width: 95%;
207 margin: 0 auto 15px;
208 background: -moz-linear-gradient(center top , #FFFFFF 0%, #F5F5F5 100%) repeat scroll 0 0 transparent;
209 border: 1px solid #DFDFDF;
210 padding: 8px;
211 -webkit-box-sizing: border-box;
212 -moz-box-sizing: border-box;
213 box-sizing: border-box;
214}
215
216/* Elements
217---------------------------------------------------------------------------- */
218
219.project_list,
220.shortlog,
221.tree,
222.commit_search,
223.history {
224 width: 95%;
225 margin: 0 auto 15px auto;
226 border: 1px solid #d8d8d8;
227 -moz-box-shadow: 0 0 3px rgba(0,0,0,0.2);
228 -webkit-box-shadow: 0 0 3px rgba(0,0,0,0.2);
229 box-shadow: 0 0 3px rgba(0,0,0,0.2);
230}
231
232.project_list th,
233.shortlog th,
234.tree th,
235.commit_search th {
236 color: #afafaf;
237 font-weight: normal;
238}
239
240.project_list th {
241 font-weight: bold;
242}
243
244.project_list tr,
245.shortlog tr,
246.tree tr,
247.commit_search tr {
248 background: #eaeaea;
249 height: 2.5em;
250 text-align: left;
251 color: #545454;
252}
253
254.project_list tr.dark, .project_list tr.light,
255.shortlog tr.dark, .shortlog tr.light,
256.tree tr.dark, .tree tr.light,
257.commit_search tr.dark, .commit_search tr.light,
258.history tr.dark, .history tr.light,
259.heads tr.dark, .heads tr.light {
260 background: #F9F9F9; /* old browsers */
261 background: -moz-linear-gradient(top, #F9F9F9 0%, #EFEFEF 100%); /* firefox */
262 background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#F9F9F9), color-stop(100%,#EFEFEF)); /* webkit */
263 filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F9F9F9', endColorstr='#EFEFEF',GradientType=0 ); /* ie */
264 background: -o-linear-gradient(top, #F9F9F9 0%, #EFEFEF 100%);
265 height: 2.5em;
266 border-bottom: 1px solid #e1e1e1;
267}
268
269th .header {
270 background: transparent;
271 border: 0;
272 padding: 0;
273 font-weight: bold;
274}
275
276.tree {
277 width: 100%;
278 margin: 0;
279}
280
281.projsearch {
282 position: absolute;
283 right: 4%;
284 top: 15px;
285}
286
287.projsearch a {
288 display: none;
289}
290
291.commit_search {
292 background: #eaeaea;
293}
294
295.page_nav,
296.list_head,
297.page_path,
298.search {
299 width: 94%;
300 background: #eaeaea;
301 color: #545454;
302 border: 1px solid #d8d8d8;
303 padding: 5px;
304 margin: 0 auto 15px auto;
305}
306
307.history {
308 background: #eaeaea;
309}
310
311.title {
312 margin: 0 auto 15px auto;
313 padding: 5px;
314 width: 95%;
315}
316
317.readme {
318 background: #eaf2f5;
319 border: 1px solid #bedce7;
320 -moz-box-sizing: border-box;
321 -webkit-box-sizing: border-box;
322 box-sizing: border-box;
323 margin: 0 auto 15px auto;
324 padding: 15px;
325 width: 95%;
326}
327
328.readme h1 {
329 display: block;
330 font-size: 2em;
331 font-weight: bold;
332 margin-bottom: 0.67em;
333 margin-top: 0;
334}
335
336.readme h2 {
337 font-size: 1.5em;
338 font-weight: bold;
339 margin-bottom: 0.83em;
340}
341
342
343.readme h3 {
344 font-size: 1.17em;
345 font-weight: bold;
346 margin-bottom: 1em;
347}
348
349.readme p {
350 margin-bottom: 1em;
351}
352
353.readme ul {
354 list-style: disc;
355 margin-bottom: 1em;
356 margin-left: 1.5em;
357}
358
359.readme ul ul {
360 margin-bottom: 0;
361}
362
363.readme ol {
364 list-style: decimal;
365 margin-bottom: 1em;
366 margin-left: 1.5em;
367}
368
369.readme ol ol {
370 margin-bottom: 0;
371}
372
373.readme pre {
374 font-family: monospace;
375 margin: 1em 0;
376 white-space: pre;
377}
378
379.readme tt, .readme code, .readme kbd, .readme samp {
380 font-family: monospace;
381}
382
383.readme blockquote {
384 margin: 1em;
385}
386
387.projects_list,
388.tags {
389 width: 95%;
390 background: #f0f0f0;
391 color: #545454;
392 border: 1px solid #d8d8d8;
393 padding: 5px;
394 margin: 0 auto 15px auto;
395}
396
397.heads {
398 width: 95%;
399 color: #545454;
400 border: 1px solid #d8d8d8;
401 padding: 5px;
402 margin: 0 auto 15px auto;
403}
404
405.header {
406 width: 94%;
407 margin: 0 auto 15px auto;
408 background: #eaf2f5;
409 border: 1px solid #bedce7;
410 padding: 5px;
411}
412
413.header .age {
414 float: left;
415 color: #000;
416 font-weight: bold;
417 width: 10em;
418}
419
420.title_text {
421 width: 94%;
422 background: #eaf2f5;
423 border: 1px solid #bedce7;
424 padding: 5px;
425 margin: 0 auto 0 auto;
426}
427
428.log_body {
429 width: 94%;
430 background: #eaf2f5;
431 border: 1px solid #bedce7;
432 border-top: 0;
433 padding: 5px;
434 margin: 0 auto 15px auto;
435}
436
437.page_body {
438 line-height: 1.4em;
439 width: 94%;
440 background: #f8f8f8;
441 border: 1px solid #d8d8d8;
442 padding: 5px;
443 margin: 15px auto 15px auto;
444}
445
446.diff_tree {
447 width: 95%;
448 background: #f0f0f0;
449 border: 1px solid #d8d8d8;
450 padding: 5px;
451 margin: 0 auto 15px auto;
452}
453
454.page_body > .list_head {
455 width: 98.5%;
456}
457
458.page_body > .diff_tree {
459 width: 99.5%;
460}
461
462.patch > .header {
463 width: 99%;
464}
465
466.author .avatar,
467.author_date .avatar {
468 position: relative;
469 top: 3px;
470}
471
472.object_header .avatar {
473 border: 1px solid #D8D8D8;
474 float: right;
475}
476
477.object_header td,
478.object_header th {
479 vertical-align: top;
480}
481
482/* Refs
483---------------------------------------------------------------------------- */
484
485span.refs span {
486 color: #707070;
487 display: inline-block;
488 margin: 0;
489 background-color: #eee;
490 border: 1px solid #ccc;
491 border-radius: 3px;
492 height: 18px;
493 padding: 0 6px;
494 text-overflow: ellipsis;
495}
496
497span.refs span.ref {
498 color: #707070;
499 display: inline-block;
500 margin: 0;
501 background-color: #c4c4ff;
502 border: 1px solid #7878ff;
503 border-radius: 3px;
504 height: 18px;
505 padding: 0 6px;
506 text-overflow: ellipsis;
507 background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gIKFSUnpolg7AAAAHJQTFRFAAAAVVWqZmbMVVXVYGDgbW3td3fuc3PzdHT0cHD1d3f6dHT6dnb7dHT7dnb8dnb8dnb9d3f9dnb+eHj+d3f+eHj+d3f+d3f+d3f+eHj+d3f+eHj+d3f+eHj+d3f+d3f+eHj+d3f+d3f+d3f+eHj/////V9oQhQAAACR0Uk5TAAIEBQcNDhMVGCotNTZAT217i5CgobvExtjZ4eLr7vP09ff7uqQ6cgAAAAFiS0dEJcMByQ8AAABUSURBVBjTpc43AoAwDENRh95bgNBM1f3PyOpslD++RSJ61YgH5M2IbIkn4GocSR1MZVBL4t2n4FgkbaxI8Sqph041WknZCWAIrcmEUbpf3lNe0N9u59YFYHnZ78gAAAAASUVORK5CYII=);
508 background-repeat: no-repeat;
509 padding-left: 18px;
510}
511
512span.refs span.tag {
513 color: #707070;
514 display: inline-block;
515 margin: 0;
516 background-color: #ffffab;
517 border: 1px solid #d9d93b;
518 border-radius: 3px;
519 height: 18px;
520 padding: 0 6px;
521 text-overflow: ellipsis;
522 background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gIKFSUZZ+h9RwAAAGZQTFRFAAAAtrYkwMBAwMBAx8c4yso11NQ71NQ51dU52Ng71tY519c719c719c62Ng719c719c62Ng72dk62Ng62Ng72Ng72dk62Ng72Ng62dk62dk72dk62Ng62dk72Ng72Ng72dk7////ou/AnQAAACB0Uk5TAAYHCxESLjRCWWlqa4uNkpissbrO19jc3ufs8vf6/f7atAU2AAAAAWJLR0QhxGwNFgAAAF1JREFUGFeNy0cOgCAABVGw94rY5d//lC7omhhn+ZIh5Gf1xPk0Zi5dAABROIQjSU/fsAXhDkCUljAv8jW2wlQpaixpo4Nj+dtatVpjkSJjLNaizRVpvhBCu/4h391jzw1lU12Z7wAAAABJRU5ErkJggg==);
523 background-repeat: no-repeat;
524 padding-left: 18px;
525}
526
527span.refs span.head {
528 color: #707070;
529 display: inline-block;
530 margin: 0;
531 background-color: #c4ffc4;
532 border: 1px solid #78ff78;
533 border-radius: 3px;
534 height: 18px;
535 padding: 0 6px;
536 text-overflow: ellipsis;
537 background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gIKFSYDsafX/gAAAUpJREFUOMvVkjFLA0EQhd/s7l06MSCihbV/wC5/QBDEIFYWprRIIQQJFqKFQi4kUbBQsFSwtrUQLQULUTBFLCzVIgimCXe7z0q5yIWcqfRVwzDzMTNvgL8mSUqWw3JOtFQJdsIwLDYyjdYgkEmkazl2oVtQWk36nn8AYBYASmFpxmizGtnoqO7Vb+M9KglEkASdpWU872nvVCiPRpuTnz2JIHGyqX3d0kZfR1G0Ht+g/do+FIhOBbLW3n/FNb/28D0puZ+dyL44ur1UoH5yzt2JyIj6UGdDgwrPhYzSagNEszJaeU/lWlylbmnaeGZZICsAppxzi6nt73HK85oQCMknOuarpno+FIjglVjZDXaCS2yDv3rIHlCb88FY0BlUl3hs7ektkhckb5DFWhoz+n12zr7ZPLpYUqLm0oBMn8NUzLhpAgjpWMS/1CcSJ3ykD7Rk1QAAAABJRU5ErkJggg==);
538 background-repeat: no-repeat;
539 padding-left: 18px;
540}
541
542span.refs a {
543 color: #4e4e4e;
544 font: 11px "Bitstream Vera Sans Mono", "DejaVu Sans Mono", Monaco, monospace;
545 line-height: 18px;
546}
547
548/* Diffs
549---------------------------------------------------------------------------- */
550
551div.diff.to_file a.path,
552div.diff.to_file {
553 color: #007000;
554}
555
556div.diff.from_file a.path,
557div.diff.from_file {
558 color: #aa0000;
559}
560
561.patch .header {
562 margin: 0;
563}
564
565.patchset {
566 overflow-x: auto;
567 overflow-y: hidden;
568}
569
570.chunk_header {
571 background: #eaf2f5;
572 color: #999;
573}
574
575.rem {
576 background: #ffdddd;
577}
578.rem .marked {
579 background: #ffaaaa;
580}
581.add {
582 background: #ddffdd;
583}
584.add .marked {
585 background: #7dff7d;
586}
587
588.extended_header {
589 width: 99.5%;
590}
591
592div.chunk_block {
593 overflow: hidden;
594}
595
596div.chunk_block div.old {
597 float: left;
598 width: 50%;
599 overflow: hidden;
600 border-right: 5px solid #EAF2F5;
601}
602
603div.chunk_block.rem,
604div.chunk_block.add {
605 background: transparent;
606}
607
608div.chunk_block div.old .add,
609div.chunk_block div.old .rem {
610 padding-right: 3px;
611}
612
613div.chunk_block div.new .add,
614div.chunk_block div.new .rem {
615 padding-left: 3px;
616}
617
618div.chunk_block div.new {
619 margin-left: 50%;
620 width: 50%;
621 border-left: 5px solid #EAF2F5;
622}
623
624/* Category
625---------------------------------------------------------------------------- */
626
627td.category {
628 background: #E6F1F6; /* old browsers */
629 background: -moz-linear-gradient(top, #C8D8E7 0%, #E6F1F3 100%); /* firefox */
630 background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#C8D8E7), color-stop(100%,#E6F1F3)); /* webkit */
631 filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#C8D8E7', endColorstr='#E6F1F3',GradientType=0 ); /* ie */
632 background: -o-linear-gradient(top, #C8D8E7 0%, #E6F1F3 100%);
633 font-weight: bold;
634 border-bottom: 1px solid #D1D1D1;
635 border-top: 1px solid #D1D1D1;
636}
637
638/* Age
639---------------------------------------------------------------------------- */
640
641/* noage: "No commits" */
642.project_list td.noage {
643 color: #cdcdcd;
644}
645
646/* age2: 60*60*24*2 <= age */
647.project_list td.age2, .blame td.age2 {
648 color: #545454;
649}
650
651/* age1: 60*60*2 <= age < 60*60*24*2 */
652.project_list td.age1 {
653 color: #009900;
654}
655
656/* age0: age < 60*60*2 */
657.project_list td.age0 {
658 color: #009900;
659 font-weight: bold;
660}
661
662/* File status
663---------------------------------------------------------------------------- */
664
665.diff_tree span.file_status.new {
666 color: #008000;
667}
668
669table.diff_tree span.file_status.deleted {
670 color: #c00000;
671}
672
673table.diff_tree span.file_status.moved,
674table.diff_tree span.file_status.mode_chnge {
675 color: #545454;
676}
677
678table.diff_tree span.file_status.copied {
679 color: #70a070;
680}
681
682span.cntrl {
683 border: dashed #aaaaaa;
684 border-width: 1px;
685 padding: 0px 2px 0px 2px;
686 margin: 0px 2px 0px 2px;
687}
688
689span.match {
690 background: #aaffaa;
691 color: #000;
692}
693
694td.error {
695 color: red;
696 background: yellow;
697}
698
699/* blob view */
700
701td.pre, div.pre, div.diff {
702 white-space: pre-wrap;
703}
704
705/* JavaScript-based timezone manipulation */
706
707.popup { /* timezone selection UI */
708 position: absolute;
709 /* "top: 0; right: 0;" would be better, if not for bugs in browsers */
710 top: 0; left: 0;
711 border: 1px solid #d8d8d8;
712 padding: 2px;
713 background-color: #f0f0f0;
714 font-style: normal;
715 color: #545454;
716 cursor: auto;
717}
718
719.close-button { /* close timezone selection UI without selecting */
720 /* float doesn't work within absolutely positioned container,
721 * if width of container is not set explicitly */
722 /* float: right; */
723 position: absolute;
724 top: 0px; right: 0px;
725 border: 1px solid #ffaaaa;
726 margin: 1px 1px 1px 1px;
727 padding-bottom: 2px;
728 width: 12px;
729 height: 10px;
730 font-size: 9px;
731 font-weight: bold;
732 text-align: center;
733 background-color: #ffdddd;
734 cursor: pointer;
735}
736
737/* Style definition generated by highlight 2.4.5, http://www.andre-simon.de/ */
738
739/* Highlighting theme definition: */
740
741.num { color:#6ecf36; }
742.esc { color:#ff00ff; }
743.str { color:#ff00d3; background-color: #edc9ec }
744.dstr { color:#818100; }
745.slc { color:#838183; font-style:italic; }
746.com { color:#838183; font-style:italic; }
747.dir { color:#008200; }
748.sym { color:#000000; }
749.line { color:#555555; }
750.kwa { color:#666666; font-weight:bold; }
751.kwb { color:#6b3099; }
752.kwc { color:#d4663d; }
753.kwd { color:#2928ff; }
754
755/**** Styles supplémentaires *****/
756
757.readme div.toc {
758 float: right;
759 border: 1px solid black;
760 background-color: white;
761}
762.readme div.toc span.toctitle {
763 display: inline-block;
764 width: 100%;
765 text-align: center;
766 font-weight: bold;
767}
768
769.readme table {
770 background-color: white;
771}
772
773.readme table thead tr {
774 background-color: #ccc;
775}
776
777.readme table tbody tr:nth-child(2n) {
778 background-color: #f8f8f8;
779}
780
781.readme table td, .readme table th {
782 border: 1px solid black;
783}
diff --git a/overlays/gitweb/theme/gitweb.js b/overlays/gitweb/theme/gitweb.js
deleted file mode 100644
index 72f3cfa..0000000
--- a/overlays/gitweb/theme/gitweb.js
+++ /dev/null
@@ -1,27 +0,0 @@
1function include(filename, onload) {
2 var head = document.getElementsByTagName('head')[0];
3 var script = document.createElement('script');
4 script.src = filename;
5 script.type = 'text/javascript';
6 script.onload = script.onreadystatechange = function() {
7 if (script.readyState) {
8 if (script.readyState === 'complete' || script.readyState === 'loaded') {
9 script.onreadystatechange = null;
10 onload();
11 }
12 }
13 else {
14 onload();
15 }
16 }
17 head.appendChild(script);
18}
19
20include('static/gitweb.js', function() {});
21include('//code.jquery.com/jquery-3.1.0.min.js', function() {
22 $("div.title").each(function(index, element) {
23 if ($(element).text() === "readme" || $(element).text() === " ") {
24 $(element).hide();
25 }
26 });
27});
diff --git a/overlays/goaccess/default.nix b/overlays/goaccess/default.nix
deleted file mode 100644
index 6b9758b..0000000
--- a/overlays/goaccess/default.nix
+++ /dev/null
@@ -1,13 +0,0 @@
1self: super: {
2 goaccess = super.goaccess.overrideAttrs(old: rec {
3 name = "goaccess-${version}";
4 version = "1.4";
5 src = self.fetchurl {
6 url = "https://tar.goaccess.io/${name}.tar.gz";
7 sha256 = "1gkpjg39f3afdwm9128jqjsfap07p8s027czzlnxfmi5hpzvkyz8";
8 };
9 configureFlags = old.configureFlags ++ [ "--enable-tcb=btree" ];
10 buildInputs = old.buildInputs ++ [ self.tokyocabinet self.bzip2 ];
11 });
12
13}
diff --git a/overlays/kanboard/default.nix b/overlays/kanboard/default.nix
deleted file mode 100644
index 05f2882..0000000
--- a/overlays/kanboard/default.nix
+++ /dev/null
@@ -1,18 +0,0 @@
1self: super: {
2 kanboard = { kanboard_config ? "/etc/kanboard/config.php" }:
3 super.kanboard.overrideAttrs(old: rec {
4 name = "kanboard-${version}";
5 version = "1.2.9";
6 src = self.fetchFromGitHub {
7 owner = "kanboard";
8 repo = "kanboard";
9 rev = "c4152316b14936556edf3bcc4d11f16ba31b8ae7";
10 sha256 = "1hdr95cpxgdzrzhffs63gdl0g7122ma2zg8bkqwp42p5xphx0xan";
11 };
12 installPhase = ''
13 cp -a . $out
14 ln -s ${kanboard_config} $out/config.php
15 mv $out/data $out/dataold
16 '';
17 });
18}
diff --git a/overlays/khal/default.nix b/overlays/khal/default.nix
deleted file mode 100644
index 597cc0e..0000000
--- a/overlays/khal/default.nix
+++ /dev/null
@@ -1,8 +0,0 @@
1self: super: {
2 khal = super.khal.overridePythonAttrs(old: {
3 postPatch = ''
4 sed -i "s/Invalid value for \"ics\"/Invalid value for \\\'ics\\\'/" tests/cli_test.py
5 sed -i "s/Invalid value for \"\[ICS\]\"/Invalid value for \\\'[ICS]\\\'/" tests/cli_test.py
6 '';
7 });
8}
diff --git a/overlays/ledger/default.nix b/overlays/ledger/default.nix
deleted file mode 100644
index 9f2df57..0000000
--- a/overlays/ledger/default.nix
+++ /dev/null
@@ -1,20 +0,0 @@
1self: super: {
2 ledger = super.ledger.overrideAttrs(old: rec {
3 #name = "${old.pname}-${version}";
4 #version = "3.2.1";
5 #src = self.fetchFromGitHub {
6 # owner = "ledger";
7 # repo = "ledger";
8 # rev = "v${version}";
9 # sha256 = "0x6jxwss3wwzbzlwmnwb8yzjk8f9wfawif4f1b74z2qg6hc4r7f6";
10 #};
11 patches = old.patches or [] ++ [
12 (self.fetchpatch {
13 name = "xdgconfig.patch";
14 url = "https://github.com/ledger/ledger/commit/c79674649dee7577d6061e3d0776922257520fd0.patch";
15 sha256 = "0n82mjz9i17800r7vs45sxpss14rivsf1j8hrv7jal24iyfm01dz";
16 excludes = [ "doc/NEWS.md" ];
17 })
18 ];
19 });
20}
diff --git a/overlays/lesspipe/default.nix b/overlays/lesspipe/default.nix
deleted file mode 100644
index e53feae..0000000
--- a/overlays/lesspipe/default.nix
+++ /dev/null
@@ -1,5 +0,0 @@
1self: super: {
2 lesspipe = super.lesspipe.overrideAttrs(old: {
3 configureFlags = (old.configureFlags or []) ++ [ "--yes" ];
4 });
5}
diff --git a/overlays/morph/default.nix b/overlays/morph/default.nix
deleted file mode 100644
index 448f051..0000000
--- a/overlays/morph/default.nix
+++ /dev/null
@@ -1,5 +0,0 @@
1self: super: {
2 morph = super.morph.overrideAttrs(old: {
3 patches = (old.patches or []) ++ [ ./verbose_nix.patch ./dry-run.patch ];
4 });
5}
diff --git a/overlays/morph/dry-run.patch b/overlays/morph/dry-run.patch
deleted file mode 100644
index 2ff099e..0000000
--- a/overlays/morph/dry-run.patch
+++ /dev/null
@@ -1,59 +0,0 @@
1diff --git a/morph.go b/morph.go
2index a88414b..e5894df 100644
3--- a/morph.go
4+++ b/morph.go
5@@ -542,6 +542,7 @@ func getNixContext() *nix.NixContext {
6 return &nix.NixContext{
7 EvalMachines: filepath.Join(assetRoot, assets.Friendly, "eval-machines.nix"),
8 ShowTrace: showTrace,
9+ DryRun: *dryRun,
10 KeepGCRoot: *keepGCRoot,
11 AllowBuildShell: *allowBuildShell,
12 }
13@@ -574,8 +575,10 @@ func buildHosts(hosts []nix.Host) (resultPath string, err error) {
14 return
15 }
16
17- fmt.Fprintln(os.Stderr, "nix result path: ")
18- fmt.Println(resultPath)
19+ if resultPath != "" {
20+ fmt.Fprintln(os.Stderr, "nix result path: ")
21+ fmt.Println(resultPath)
22+ }
23 return
24 }
25
26diff --git a/nix/nix.go b/nix/nix.go
27index 6a9cfd5..0f7884b 100644
28--- a/nix/nix.go
29+++ b/nix/nix.go
30@@ -49,6 +49,7 @@ type Deployment struct {
31 type NixContext struct {
32 EvalMachines string
33 ShowTrace bool
34+ DryRun bool
35 KeepGCRoot bool
36 AllowBuildShell bool
37 }
38@@ -269,6 +270,10 @@ func (ctx *NixContext) BuildMachines(deploymentPath string, hosts []Host, nixArg
39 args = append(args, "--show-trace")
40 }
41
42+ if ctx.DryRun {
43+ args = append(args, "--dry-run")
44+ }
45+
46 if nixBuildTargets != "" {
47 args = append(args,
48 "--arg", "buildTargets", nixBuildTargets)
49@@ -308,6 +313,10 @@ func (ctx *NixContext) BuildMachines(deploymentPath string, hosts []Host, nixArg
50 return resultPath, errors.New(errorMessage)
51 }
52
53+ if ctx.DryRun {
54+ return "", err
55+ }
56+
57 resultPath, err = os.Readlink(resultLinkPath)
58 if err != nil {
59 return "", err
diff --git a/overlays/morph/verbose_nix.patch b/overlays/morph/verbose_nix.patch
deleted file mode 100644
index 389a79c..0000000
--- a/overlays/morph/verbose_nix.patch
+++ /dev/null
@@ -1,12 +0,0 @@
1diff --git a/nix/nix.go b/nix/nix.go
2index bb63870..7fe04aa 100644
3--- a/nix/nix.go
4+++ b/nix/nix.go
5@@ -347,6 +347,7 @@ func Push(ctx *ssh.SSHContext, host Host, paths ...string) (err error) {
6 options := mkOptions(host)
7 for _, path := range paths {
8 args := []string{
9+ "-v",
10 "copy",
11 path,
12 "--to", "ssh://" + userArg + host.TargetHost + keyArg,
diff --git a/overlays/neomutt/default.nix b/overlays/neomutt/default.nix
deleted file mode 100644
index f03290a..0000000
--- a/overlays/neomutt/default.nix
+++ /dev/null
@@ -1,7 +0,0 @@
1self: super: {
2 neomutt = super.neomutt.overrideAttrs(old: {
3 patches = old.patches or [] ++ [
4 ./tx.patch
5 ];
6 });
7}
diff --git a/overlays/neomutt/tx.patch b/overlays/neomutt/tx.patch
deleted file mode 100644
index c8736df..0000000
--- a/overlays/neomutt/tx.patch
+++ /dev/null
@@ -1,44 +0,0 @@
1commit 61ae454e1579d02736c48e3468a3237429214cdf
2Author: Ismaël Bouya <ismael.bouya@normalesup.org>
3Date: Tue Jun 2 13:03:04 2020 +0200
4
5 Add %tx to index_format
6
7diff --git a/hdrline.c b/hdrline.c
8index 9224c6641..1594ed729 100644
9--- a/hdrline.c
10+++ b/hdrline.c
11@@ -575,6 +575,7 @@ static const char *index_format_str(char *buf, size_t buflen, size_t col, int co
12 const struct Address *from = TAILQ_FIRST(&e->env->from);
13 const struct Address *to = TAILQ_FIRST(&e->env->to);
14 const struct Address *cc = TAILQ_FIRST(&e->env->cc);
15+ const struct Address *x_orig_to = TAILQ_FIRST(&e->env->x_original_to);
16
17 buf[0] = '\0';
18 switch (op)
19@@ -1192,13 +1193,18 @@ static const char *index_format_str(char *buf, size_t buflen, size_t col, int co
20
21 case 't':
22 tmp[0] = '\0';
23- if (!check_for_mailing_list(&e->env->to, "To ", tmp, sizeof(tmp)) &&
24- !check_for_mailing_list(&e->env->cc, "Cc ", tmp, sizeof(tmp)))
25- {
26- if (to)
27- snprintf(tmp, sizeof(tmp), "To %s", mutt_get_name(to));
28- else if (cc)
29- snprintf(tmp, sizeof(tmp), "Cc %s", mutt_get_name(cc));
30+ if (src[0] == 'x') {
31+ snprintf(tmp, sizeof(tmp), "%s", mutt_get_name(x_orig_to));
32+ src++;
33+ } else {
34+ if (!check_for_mailing_list(&e->env->to, "To ", tmp, sizeof(tmp)) &&
35+ !check_for_mailing_list(&e->env->cc, "Cc ", tmp, sizeof(tmp)))
36+ {
37+ if (to)
38+ snprintf(tmp, sizeof(tmp), "To %s", mutt_get_name(to));
39+ else if (cc)
40+ snprintf(tmp, sizeof(tmp), "Cc %s", mutt_get_name(cc));
41+ }
42 }
43 mutt_format_s(buf, buflen, prec, tmp);
44 break;
diff --git a/overlays/nix-direnv/default.nix b/overlays/nix-direnv/default.nix
deleted file mode 100644
index c4c96e2..0000000
--- a/overlays/nix-direnv/default.nix
+++ /dev/null
@@ -1,7 +0,0 @@
1self: super: {
2 nix-direnv = super.nix-direnv.overrideAttrs (old: {
3 postPatch = old.postPatch + ''
4 sed -i -e 's/TEMPDIR "$old_tmp"/TEMPDIR "$old_tmpdir"/' direnvrc
5 '';
6 });
7}
diff --git a/overlays/nixops/default.nix b/overlays/nixops/default.nix
deleted file mode 100644
index 14aec3b..0000000
--- a/overlays/nixops/default.nix
+++ /dev/null
@@ -1,20 +0,0 @@
1self: super: {
2 nixops = super.nixops.overrideAttrs (old: {
3 patches = [
4 ./fix_glibc.patch
5 (self.fetchpatch {
6 name = "hetzner_cloud.patch";
7 url = "https://github.com/goodraven/nixops/commit/272e50d0b0262e49cdcaad42cdab57aad183d1c2.patch";
8 sha256 = "12wcrb0155ald52m7fbr2m5rrxdnwdwripq91ckscgsk42mdc517";
9 })
10 ];
11 preConfigure = (old.preConfigure or "") + ''
12 # https://github.com/NixOS/nixops/issues/1216
13 sed -i -e "/Register the paths in the Nix database./s/#.*$/export USER=root/" nix/libvirtd-image.nix
14
15 sed -i -e '/^import sys$/s/$/; sys.tracebacklimit = 0/' scripts/nixops
16 sed -i -e "/'keyFile'/s/'path'/'string'/" nixops/backends/__init__.py
17 sed -i -e "/security.initialRootPassword/d" nix/hetzner.nix
18 '';
19 });
20}
diff --git a/overlays/nixops/fix_glibc.patch b/overlays/nixops/fix_glibc.patch
deleted file mode 100644
index 1aeb093..0000000
--- a/overlays/nixops/fix_glibc.patch
+++ /dev/null
@@ -1,15 +0,0 @@
1diff --git a/nix/hetzner-bootstrap.nix b/nix/hetzner-bootstrap.nix
2index 035e6f9..def42a1 100644
3--- a/nix/hetzner-bootstrap.nix
4+++ b/nix/hetzner-bootstrap.nix
5@@ -3,9 +3,7 @@ with import <nixpkgs> { system = "x86_64-linux"; };
6 let
7 pkgsNative = import <nixpkgs> {};
8
9- nixpart = python2Packages.nixpart0.override {
10- useNixUdev = false;
11- };
12+ nixpart = python2Packages.nixpart0;
13
14 generateConfig = (import <nixpkgs/nixos> {
15 configuration = {};
diff --git a/overlays/nixops/hetzner_cloud.patch b/overlays/nixops/hetzner_cloud.patch
deleted file mode 100644
index b75c116..0000000
--- a/overlays/nixops/hetzner_cloud.patch
+++ /dev/null
@@ -1,480 +0,0 @@
1From 272e50d0b0262e49cdcaad42cdab57aad183d1c2 Mon Sep 17 00:00:00 2001
2From: goodraven
3 <employee-pseudonym-7f597def-7eeb-47f8-b10a-0724f2ba59a9@google.com>
4Date: Thu, 3 May 2018 22:24:58 -0700
5Subject: [PATCH] Initial commit adding support for hetzner cloud
6
7This is based on the digital ocean backend. It also uses nixos-infect. I extended nixos-infect to be generic
8for both backends.
9
10Fixes #855
11---
12 examples/trivial-hetzner-cloud.nix | 12 ++
13 nix/eval-machine-info.nix | 1 +
14 nix/hetzner-cloud.nix | 56 +++++++
15 nix/options.nix | 1 +
16 nixops/backends/hetzner_cloud.py | 230 +++++++++++++++++++++++++++++
17 nixops/data/nixos-infect | 77 +++++++---
18 6 files changed, 354 insertions(+), 23 deletions(-)
19 create mode 100644 examples/trivial-hetzner-cloud.nix
20 create mode 100644 nix/hetzner-cloud.nix
21 create mode 100644 nixops/backends/hetzner_cloud.py
22
23diff --git a/examples/trivial-hetzner-cloud.nix b/examples/trivial-hetzner-cloud.nix
24new file mode 100644
25index 000000000..c61add6bb
26--- /dev/null
27+++ b/examples/trivial-hetzner-cloud.nix
28@@ -0,0 +1,12 @@
29+{
30+ resources.sshKeyPairs.ssh-key = {};
31+
32+ machine = { config, pkgs, ... }: {
33+ services.openssh.enable = true;
34+
35+ deployment.targetEnv = "hetznerCloud";
36+ deployment.hetznerCloud.serverType = "cx11";
37+
38+ networking.firewall.allowedTCPPorts = [ 22 ];
39+ };
40+}
41diff --git a/nix/eval-machine-info.nix b/nix/eval-machine-info.nix
42index 2884b4b47..6a7205786 100644
43--- a/nix/eval-machine-info.nix
44+++ b/nix/eval-machine-info.nix
45@@ -309,6 +309,7 @@ rec {
46 digitalOcean = optionalAttrs (v.config.deployment.targetEnv == "digitalOcean") v.config.deployment.digitalOcean;
47 gce = optionalAttrs (v.config.deployment.targetEnv == "gce") v.config.deployment.gce;
48 hetzner = optionalAttrs (v.config.deployment.targetEnv == "hetzner") v.config.deployment.hetzner;
49+ hetznerCloud = optionalAttrs (v.config.deployment.targetEnv == "hetznerCloud") v.config.deployment.hetznerCloud;
50 container = optionalAttrs (v.config.deployment.targetEnv == "container") v.config.deployment.container;
51 route53 = v.config.deployment.route53;
52 virtualbox =
53diff --git a/nix/hetzner-cloud.nix b/nix/hetzner-cloud.nix
54new file mode 100644
55index 000000000..21d148c1a
56--- /dev/null
57+++ b/nix/hetzner-cloud.nix
58@@ -0,0 +1,56 @@
59+{ config, pkgs, lib, utils, ... }:
60+
61+with utils;
62+with lib;
63+with import ./lib.nix lib;
64+
65+let
66+ cfg = config.deployment.hetznerCloud;
67+in
68+{
69+ ###### interface
70+ options = {
71+
72+ deployment.hetznerCloud.authToken = mkOption {
73+ default = "";
74+ example = "8b2f4e96af3997853bfd4cd8998958eab871d9614e35d63fab45a5ddf981c4da";
75+ type = types.str;
76+ description = ''
77+ The API auth token. We're checking the environment for
78+ <envar>HETZNER_CLOUD_AUTH_TOKEN</envar> first and if that is
79+ not set we try this auth token.
80+ '';
81+ };
82+
83+ deployment.hetznerCloud.datacenter = mkOption {
84+ example = "fsn1-dc8";
85+ default = null;
86+ type = types.nullOr types.str;
87+ description = ''
88+ The datacenter.
89+ '';
90+ };
91+
92+ deployment.hetznerCloud.location = mkOption {
93+ example = "fsn1";
94+ default = null;
95+ type = types.nullOr types.str;
96+ description = ''
97+ The location.
98+ '';
99+ };
100+
101+ deployment.hetznerCloud.serverType = mkOption {
102+ example = "cx11";
103+ type = types.str;
104+ description = ''
105+ Name or id of server types.
106+ '';
107+ };
108+ };
109+
110+ config = mkIf (config.deployment.targetEnv == "hetznerCloud") {
111+ nixpkgs.system = mkOverride 900 "x86_64-linux";
112+ services.openssh.enable = true;
113+ };
114+}
115diff --git a/nix/options.nix b/nix/options.nix
116index 0866c3ab8..db021f74d 100644
117--- a/nix/options.nix
118+++ b/nix/options.nix
119@@ -22,6 +22,7 @@ in
120 ./keys.nix
121 ./gce.nix
122 ./hetzner.nix
123+ ./hetzner-cloud.nix
124 ./container.nix
125 ./libvirtd.nix
126 ];
127diff --git a/nixops/backends/hetzner_cloud.py b/nixops/backends/hetzner_cloud.py
128new file mode 100644
129index 000000000..a2cb176b9
130--- /dev/null
131+++ b/nixops/backends/hetzner_cloud.py
132@@ -0,0 +1,230 @@
133+# -*- coding: utf-8 -*-
134+"""
135+A backend for hetzner cloud.
136+
137+This backend uses nixos-infect (which uses nixos LUSTRATE) to infect a
138+hetzner cloud instance. The setup requires two reboots, one for
139+the infect itself, another after we pushed the nixos image.
140+"""
141+import os
142+import os.path
143+import time
144+import socket
145+
146+import requests
147+
148+import nixops.resources
149+from nixops.backends import MachineDefinition, MachineState
150+from nixops.nix_expr import Function, RawValue
151+import nixops.util
152+import nixops.known_hosts
153+
154+infect_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'data', 'nixos-infect'))
155+
156+API_HOST = 'api.hetzner.cloud'
157+
158+class ApiError(Exception):
159+ pass
160+
161+class ApiNotFoundError(ApiError):
162+ pass
163+
164+class HetznerCloudDefinition(MachineDefinition):
165+ @classmethod
166+ def get_type(cls):
167+ return "hetznerCloud"
168+
169+ def __init__(self, xml, config):
170+ MachineDefinition.__init__(self, xml, config)
171+ self.auth_token = config["hetznerCloud"]["authToken"]
172+ self.location = config["hetznerCloud"]["location"]
173+ self.datacenter = config["hetznerCloud"]["datacenter"]
174+ self.server_type = config["hetznerCloud"]["serverType"]
175+
176+ def show_type(self):
177+ return "{0} [{1}]".format(self.get_type(), self.location or self.datacenter or 'any location')
178+
179+
180+class HetznerCloudState(MachineState):
181+ @classmethod
182+ def get_type(cls):
183+ return "hetznerCloud"
184+
185+ state = nixops.util.attr_property("state", MachineState.MISSING, int) # override
186+ public_ipv4 = nixops.util.attr_property("publicIpv4", None)
187+ public_ipv6 = nixops.util.attr_property("publicIpv6", None)
188+ location = nixops.util.attr_property("hetznerCloud.location", None)
189+ datacenter = nixops.util.attr_property("hetznerCloud.datacenter", None)
190+ server_type = nixops.util.attr_property("hetznerCloud.serverType", None)
191+ auth_token = nixops.util.attr_property("hetznerCloud.authToken", None)
192+ server_id = nixops.util.attr_property("hetznerCloud.serverId", None, int)
193+
194+ def __init__(self, depl, name, id):
195+ MachineState.__init__(self, depl, name, id)
196+ self.name = name
197+
198+ def get_ssh_name(self):
199+ return self.public_ipv4
200+
201+ def get_ssh_flags(self, *args, **kwargs):
202+ super_flags = super(HetznerCloudState, self).get_ssh_flags(*args, **kwargs)
203+ return super_flags + [
204+ '-o', 'UserKnownHostsFile=/dev/null',
205+ '-o', 'StrictHostKeyChecking=no',
206+ '-i', self.get_ssh_private_key_file(),
207+ ]
208+
209+ def get_physical_spec(self):
210+ return Function("{ ... }", {
211+ 'imports': [ RawValue('<nixpkgs/nixos/modules/profiles/qemu-guest.nix>') ],
212+ ('boot', 'loader', 'grub', 'device'): 'nodev',
213+ ('fileSystems', '/'): { 'device': '/dev/sda1', 'fsType': 'ext4'},
214+ ('users', 'extraUsers', 'root', 'openssh', 'authorizedKeys', 'keys'): [self.depl.active_resources.get('ssh-key').public_key],
215+ })
216+
217+ def get_ssh_private_key_file(self):
218+ return self.write_ssh_private_key(self.depl.active_resources.get('ssh-key').private_key)
219+
220+ def create_after(self, resources, defn):
221+ # make sure the ssh key exists before we do anything else
222+ return {
223+ r for r in resources if
224+ isinstance(r, nixops.resources.ssh_keypair.SSHKeyPairState)
225+ }
226+
227+ def get_auth_token(self):
228+ return os.environ.get('HETZNER_CLOUD_AUTH_TOKEN', self.auth_token)
229+
230+ def _api(self, path, method=None, data=None, json=True):
231+ """Basic wrapper around requests that handles auth and serialization."""
232+ assert path[0] == '/'
233+ url = 'https://%s%s' % (API_HOST, path)
234+ token = self.get_auth_token()
235+ if not token:
236+ raise Exception('No hetzner cloud auth token set')
237+ headers = {
238+ 'Authorization': 'Bearer '+self.get_auth_token(),
239+ }
240+ res = requests.request(
241+ method=method,
242+ url=url,
243+ json=data,
244+ headers=headers)
245+
246+ if res.status_code == 404:
247+ raise ApiNotFoundError('Not Found: %r' % path)
248+ elif not res.ok:
249+ raise ApiError('Response for %s %s has status code %d: %s' % (method, path, res.status_code, res.content))
250+ if not json:
251+ return
252+ try:
253+ res_data = res.json()
254+ except ValueError as e:
255+ raise ApiError('Response for %s %s has invalid JSON (%s): %r' % (method, path, e, res.content))
256+ return res_data
257+
258+
259+ def destroy(self, wipe=False):
260+ if not self.server_id:
261+ self.log('server {} was never made'.format(self.name))
262+ return
263+ self.log('destroying server {} with id {}'.format(self.name, self.server_id))
264+ try:
265+ res = self._api('/v1/servers/%s' % (self.server_id), method='DELETE')
266+ except ApiNotFoundError:
267+ self.log("server not found - assuming it's been destroyed already")
268+
269+ self.public_ipv4 = None
270+ self.server_id = None
271+
272+ return True
273+
274+ def _create_ssh_key(self, public_key):
275+ """Create or get an ssh key and return an id."""
276+ public_key = public_key.strip()
277+ res = self._api('/v1/ssh_keys', method='GET')
278+ name = 'nixops-%s-%s' % (self.depl.uuid, self.name)
279+ deletes = []
280+ for key in res['ssh_keys']:
281+ if key['public_key'].strip() == public_key:
282+ return key['id']
283+ if key['name'] == name:
284+ deletes.append(key['id'])
285+ for d in deletes:
286+ # This reply is empty, so don't decode json.
287+ self._api('/v1/ssh_keys/%d' % d, method='DELETE', json=False)
288+ res = self._api('/v1/ssh_keys', method='POST', data={
289+ 'name': name,
290+ 'public_key': public_key,
291+ })
292+ return res['ssh_key']['id']
293+
294+ def create(self, defn, check, allow_reboot, allow_recreate):
295+ ssh_key = self.depl.active_resources.get('ssh-key')
296+ if ssh_key is None:
297+ raise Exception('Please specify a ssh-key resource (resources.sshKeyPairs.ssh-key = {}).')
298+
299+ self.set_common_state(defn)
300+
301+ if self.server_id is not None:
302+ return
303+
304+ ssh_key_id = self._create_ssh_key(ssh_key.public_key)
305+
306+ req = {
307+ 'name': self.name,
308+ 'server_type': defn.server_type,
309+ 'start_after_create': True,
310+ 'image': 'debian-9',
311+ 'ssh_keys': [
312+ ssh_key_id,
313+ ],
314+ }
315+
316+ if defn.datacenter:
317+ req['datacenter'] = defn.datacenter
318+ elif defn.location:
319+ req['location'] = defn.location
320+
321+ self.log_start("creating server ...")
322+ create_res = self._api('/v1/servers', method='POST', data=req)
323+ self.server_id = create_res['server']['id']
324+ self.public_ipv4 = create_res['server']['public_net']['ipv4']['ip']
325+ self.public_ipv6 = create_res['server']['public_net']['ipv6']['ip']
326+ self.datacenter = create_res['server']['datacenter']['name']
327+ self.location = create_res['server']['datacenter']['location']['name']
328+
329+ action = create_res['action']
330+ action_path = '/v1/servers/%d/actions/%d' % (self.server_id, action['id'])
331+
332+ while action['status'] == 'running':
333+ time.sleep(1)
334+ res = self._api(action_path, method='GET')
335+ action = res['action']
336+
337+ if action['status'] != 'success':
338+ raise Exception('unexpected status: %s' % action['status'])
339+
340+ self.log_end("{}".format(self.public_ipv4))
341+
342+ self.wait_for_ssh()
343+ self.log_start("running nixos-infect")
344+ self.run_command('bash </dev/stdin 2>&1', stdin=open(infect_path))
345+ self.reboot_sync()
346+
347+ def reboot(self, hard=False):
348+ if hard:
349+ self.log("sending hard reset to server...")
350+ res = self._api('/v1/servers/%d/actions/reset' % self.server_id, method='POST')
351+ action = res['action']
352+ action_path = '/v1/servers/%d/actions/%d' % (self.server_id, action['id'])
353+ while action['status'] == 'running':
354+ time.sleep(1)
355+ res = self._api(action_path, method='GET')
356+ action = res['action']
357+ if action['status'] != 'success':
358+ raise Exception('unexpected status: %s' % action['status'])
359+ self.wait_for_ssh()
360+ self.state = self.STARTING
361+ else:
362+ MachineState.reboot(self, hard=hard)
363diff --git a/nixops/data/nixos-infect b/nixops/data/nixos-infect
364index 66634357b..437a2ec61 100644
365--- a/nixops/data/nixos-infect
366+++ b/nixops/data/nixos-infect
367@@ -68,26 +68,49 @@ makeConf() {
368 }
369 EOF
370 # (nixos-generate-config will add qemu-user and bind-mounts, so avoid)
371+ local disk
372+ if [ -e /dev/sda ]; then
373+ disk=/dev/sda
374+ else
375+ disk=/dev/vda
376+ fi
377 cat > /etc/nixos/hardware-configuration.nix << EOF
378 { ... }:
379 {
380 imports = [ <nixpkgs/nixos/modules/profiles/qemu-guest.nix> ];
381- boot.loader.grub.device = "/dev/vda";
382- fileSystems."/" = { device = "/dev/vda1"; fsType = "ext4"; };
383+ boot.loader.grub.device = "${disk}";
384+ fileSystems."/" = { device = "${disk}1"; fsType = "ext4"; };
385 }
386 EOF
387
388 local IFS=$'\n'
389- ens3_ip4s=($(ip address show dev eth0 | grep 'inet ' | sed -r 's|.*inet ([0-9.]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|'))
390- ens3_ip6s=($(ip address show dev eth0 | grep 'inet6 .*global' | sed -r 's|.*inet6 ([0-9a-f:]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|'))
391- ens4_ip4s=($(ip address show dev eth1 | grep 'inet ' | sed -r 's|.*inet ([0-9.]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|'))
392- ens4_ip6s=($(ip address show dev eth1 | grep 'inet6 .*global' | sed -r 's|.*inet6 ([0-9a-f:]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|'))
393- gateway=($(ip route show dev eth0 | grep default | sed -r 's|default via ([0-9.]+).*|\1|'))
394- gateway6=($(ip -6 route show dev eth0 | grep default | sed -r 's|default via ([0-9a-f:]+).*|\1|'))
395- ether0=($(ip address show dev eth0 | grep link/ether | sed -r 's|.*link/ether ([0-9a-f:]+) .*|\1|'))
396- ether1=($(ip address show dev eth1 | grep link/ether | sed -r 's|.*link/ether ([0-9a-f:]+) .*|\1|'))
397+ gateway=($(ip route show | grep default | sed -r 's|default via ([0-9.]+).*|\1|'))
398+ gateway6=($(ip -6 route show | grep default | sed -r 's|default via ([0-9a-f:]+).*|\1|'))
399+ interfaces=($(ip link | awk -F ': ' '/^[0-9]*: / {if ($2 != "lo") {print $2}}'))
400 nameservers=($(grep ^nameserver /etc/resolv.conf | cut -f2 -d' '))
401
402+ # Predict the predictable name for each interface since that is enabled in
403+ # the nixos system.
404+ declare -A predictable_names
405+ for interface in ${interfaces[@]}; do
406+ # udevadm prints out the candidate names which will be selected if
407+ # available in this order.
408+ local name=$(udevadm info /sys/class/net/$interface | awk -F = '
409+ /^E: ID_NET_NAME_FROM_DATABASE=/ {arr[1]=$2}
410+ /^E: ID_NET_NAME_ONBOARD=/ {arr[2]=$2}
411+ /^E: ID_NET_NAME_SLOT=/ {arr[3]=$2}
412+ /^E: ID_NET_NAME_PATH=/ {arr[4]=$2}
413+ /^E: ID_NET_NAME_MAC=/ {arr[5]=$2}
414+ END {for (i=1;i<6;i++) {if (length(arr[i]) > 0) { print arr[i]; break}}}')
415+ if [ -z "$name" ]; then
416+ echo Could not determine predictable name for interface $interface
417+ fi
418+ predictable_names[$interface]=$name
419+ done
420+
421+ # Take a gamble on the first interface being able to reach the gateway.
422+ local default_interface=${predictable_names[${interfaces[0]}]}
423+
424 cat > /etc/nixos/networking.nix << EOF
425 { ... }: {
426 # This file was populated at runtime with the networking
427@@ -96,25 +119,27 @@ EOF
428 nameservers = [$(for a in ${nameservers[@]}; do echo -n "
429 \"$a\""; done)
430 ];
431- defaultGateway = "${gateway}";
432- defaultGateway6 = "${gateway6}";
433+ defaultGateway = {address = "${gateway}"; interface = "${default_interface}";};
434+ defaultGateway6 = {address = "${gateway6}"; interface = "${default_interface}";};
435 interfaces = {
436- ens3 = {
437- ip4 = [$(for a in ${ens3_ip4s[@]}; do echo -n "
438- $a"; done)
439- ];
440- ip6 = [$(for a in ${ens3_ip6s[@]}; do echo -n "
441- $a"; done)
442- ];
443- };
444- ens4 = {
445- ip4 = [$(for a in ${ens4_ip4s[@]}; do echo -n "
446+EOF
447+
448+ for interface in ${interfaces[@]}; do
449+ ip4s=($(ip address show dev $interface | grep 'inet ' | sed -r 's|.*inet ([0-9.]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|'))
450+ ip6s=($(ip address show dev $interface | grep 'inet6 .*global' | sed -r 's|.*inet6 ([0-9a-f:]+)/([0-9]+).*|{ address="\1"; prefixLength=\2; }|'))
451+ cat >> /etc/nixos/networking.nix << EOF
452+ ${predictable_names[$interface]} = {
453+ ip4 = [$(for a in ${ip4s[@]}; do echo -n "
454 $a"; done)
455 ];
456- ip6 = [$(for a in ${ens4_ip6s[@]}; do echo -n "
457+ ip6 = [$(for a in ${ip6s[@]}; do echo -n "
458 $a"; done)
459 ];
460 };
461+EOF
462+ done
463+
464+ cat >> /etc/nixos/networking.nix << EOF
465 };
466 };
467 }
468@@ -154,6 +179,12 @@ export HOME="/root"
469 groupadd -r nixbld -g 30000
470 seq 1 10 | xargs -I{} useradd -c "Nix build user {}" -d /var/empty -g nixbld -G nixbld -M -N -r -s `which nologin` nixbld{}
471
472+if ! which curl >/dev/null 2>/dev/null; then
473+ if which apt-get >/dev/null 2>/dev/null; then
474+ apt-get update && apt-get install -y curl
475+ fi
476+fi
477+
478 curl https://nixos.org/nix/install | sh
479
480 source ~/.nix-profile/etc/profile.d/nix.sh
diff --git a/overlays/pass/default.nix b/overlays/pass/default.nix
deleted file mode 100644
index ad8facd..0000000
--- a/overlays/pass/default.nix
+++ /dev/null
@@ -1,5 +0,0 @@
1self: super: {
2 pass = super.pass.overrideAttrs (old: rec {
3 patches = old.patches ++ [ ./pass-fix-pass-init.patch ];
4 });
5}
diff --git a/overlays/pass/pass-fix-pass-init.patch b/overlays/pass/pass-fix-pass-init.patch
deleted file mode 100644
index 10a76c1..0000000
--- a/overlays/pass/pass-fix-pass-init.patch
+++ /dev/null
@@ -1,42 +0,0 @@
1From 33e8f1cd0065639a948d7b5ba3f93d43bdf7f3be Mon Sep 17 00:00:00 2001
2From: =?UTF-8?q?Isma=C3=ABl=20Bouya?= <ismael.bouya@normalesup.org>
3Date: Sun, 11 Nov 2018 19:47:33 +0100
4Subject: [PATCH] Fix pass init for some gpg keys
5
6This fixes the pass init for gpg keys which have their main key as
7encryption key. This may happen for instance with RSA keys and specific
8configuration.
9---
10 src/password-store.sh | 2 +-
11 tests/t0300-reencryption.sh | 2 +-
12 2 files changed, 2 insertions(+), 2 deletions(-)
13
14diff --git a/src/password-store.sh b/src/password-store.sh
15index d89d455..44d122e 100755
16--- a/src/password-store.sh
17+++ b/src/password-store.sh
18@@ -124,7 +124,7 @@ reencrypt_path() {
19 IFS=";" eval 'GPG_RECIPIENTS+=( $group )' # http://unix.stackexchange.com/a/92190
20 unset "GPG_RECIPIENTS[$index]"
21 done
22- gpg_keys="$($GPG $PASSWORD_STORE_GPG_OPTS --list-keys --with-colons "${GPG_RECIPIENTS[@]}" | sed -n 's/^sub:[^:]*:[^:]*:[^:]*:\([^:]*\):[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[a-zA-Z]*e[a-zA-Z]*:.*/\1/p' | LC_ALL=C sort -u)"
23+ gpg_keys="$($GPG $PASSWORD_STORE_GPG_OPTS --list-keys --with-colons "${GPG_RECIPIENTS[@]}" | sed -n 's/^[ps]ub:[^:]*:[^:]*:[^:]*:\([^:]*\):[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[a-zA-Z]*e[a-zA-Z]*:.*/\1/p' | LC_ALL=C sort -u)"
24 fi
25 current_keys="$(LC_ALL=C $GPG $PASSWORD_STORE_GPG_OPTS -v --no-secmem-warning --no-permission-warning --decrypt --list-only --keyid-format long "$passfile" 2>&1 | sed -n 's/^gpg: public key is \([A-F0-9]\+\)$/\1/p' | LC_ALL=C sort -u)"
26
27diff --git a/tests/t0300-reencryption.sh b/tests/t0300-reencryption.sh
28index 3c88987..57d873f 100755
29--- a/tests/t0300-reencryption.sh
30+++ b/tests/t0300-reencryption.sh
31@@ -7,7 +7,7 @@ cd "$(dirname "$0")"
32 INITIAL_PASSWORD="will this password live? a big question indeed..."
33
34 canonicalize_gpg_keys() {
35- $GPG --list-keys --with-colons "$@" | sed -n 's/sub:[^:]*:[^:]*:[^:]*:\([^:]*\):[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[a-zA-Z]*e[a-zA-Z]*:.*/\1/p' | LC_ALL=C sort -u
36+ $GPG --list-keys --with-colons "$@" | sed -n 's/[ps]ub:[^:]*:[^:]*:[^:]*:\([^:]*\):[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[a-zA-Z]*e[a-zA-Z]*:.*/\1/p' | LC_ALL=C sort -u
37 }
38 gpg_keys_from_encrypted_file() {
39 $GPG -v --no-secmem-warning --no-permission-warning --decrypt --list-only --keyid-format long "$1" 2>&1 | grep "public key is" | cut -d ' ' -f 5 | LC_ALL=C sort -u
40--
412.19.1
42
diff --git a/overlays/pelican/default.nix b/overlays/pelican/default.nix
deleted file mode 100644
index 4f8aece..0000000
--- a/overlays/pelican/default.nix
+++ /dev/null
@@ -1,7 +0,0 @@
1self: super: {
2 pelican = with self.python3Packages;
3 pelican.overrideAttrs(old: {
4 propagatedBuildInputs = old.propagatedBuildInputs ++ [ pyyaml markdown ];
5 doInstallCheck = false;
6 });
7}
diff --git a/overlays/php-packages/default.nix b/overlays/php-packages/default.nix
deleted file mode 100644
index 90fb613..0000000
--- a/overlays/php-packages/default.nix
+++ /dev/null
@@ -1,6 +0,0 @@
1self: super: rec {
2 myPhpPackages.mysqli_pam = self.php74.extensions.mysqli.overrideAttrs(old: {
3 configureFlags = [ "--with-mysqli=${self.libmysqlclient_pam}/bin/mysql_config" "--with-mysql-sock=/run/mysqld/mysqld.sock" ];
4 patches = old.patches or [] ++ [ ./mysqli_patch.patch ];
5});
6}
diff --git a/overlays/php-packages/mysqli_patch.patch b/overlays/php-packages/mysqli_patch.patch
deleted file mode 100644
index a8f03e3..0000000
--- a/overlays/php-packages/mysqli_patch.patch
+++ /dev/null
@@ -1,11 +0,0 @@
1--- a/ext/mysqli/mysqli_nonapi.c
2+++ b/ext/mysqli/mysqli_nonapi.c
3@@ -263,7 +263,7 @@ void mysqli_common_connect(INTERNAL_FUNC
4 php_mysqli_set_error(mysql_errno(mysql->mysql), (char *) mysql_error(mysql->mysql));
5
6 #if !defined(MYSQLI_USE_MYSQLND)
7- mysql->mysql->reconnect = MyG(reconnect);
8+ mysql_options(mysql->mysql, MYSQL_OPT_RECONNECT, (my_bool *)&MyG(reconnect));
9 #endif
10
11 mysql_options(mysql->mysql, MYSQL_OPT_LOCAL_INFILE, (char *)&MyG(allow_local_infile));
diff --git a/overlays/postfix/default.nix b/overlays/postfix/default.nix
deleted file mode 100644
index c77e4cf..0000000
--- a/overlays/postfix/default.nix
+++ /dev/null
@@ -1,3 +0,0 @@
1self: super: {
2 postfix = super.postfix.override { withMySQL = true; withPgSQL = true; };
3}
diff --git a/overlays/procps-ng/default.nix b/overlays/procps-ng/default.nix
deleted file mode 100644
index 2d43a11..0000000
--- a/overlays/procps-ng/default.nix
+++ /dev/null
@@ -1,5 +0,0 @@
1self: super: {
2 procps-ng = super.procps-ng.overrideAttrs(old: {
3 configureFlags = old.configureFlags ++ [ "--enable-watch8bit" ];
4 });
5}
diff --git a/overlays/python-packages/buildbot.nix b/overlays/python-packages/buildbot.nix
deleted file mode 100644
index ccf2f6a..0000000
--- a/overlays/python-packages/buildbot.nix
+++ /dev/null
@@ -1,8 +0,0 @@
1self: super: {
2 pythonOverrides = self.buildPythonOverrides (pyself: pysuper: {
3 buildbot-plugins = pysuper.buildbot-plugins // {
4 buildslist = self.python3PackagesPlus.buildbot-plugins.buildslist;
5 };
6 buildbot-full = pysuper.buildbot-full.withPlugins [ pyself.buildbot-plugins.buildslist ];
7 }) super.pythonOverrides;
8}
diff --git a/overlays/python-packages/default.nix b/overlays/python-packages/default.nix
deleted file mode 100644
index 601eed1..0000000
--- a/overlays/python-packages/default.nix
+++ /dev/null
@@ -1,29 +0,0 @@
1let
2 fromMyPythonPackages = name: self: super: {
3 pythonOverrides = self.buildPythonOverrides (pyself: pysuper: {
4 "${name}" = self."${pyself.python.pname}PackagesPlus"."${name}";
5 }) super.pythonOverrides;
6 };
7in
8{
9 # https://github.com/NixOS/nixpkgs/issues/44426
10 # needs to come before all other in alphabetical order (or make use of
11 # lib.mkBefore)
12 __pythonOverlayFix = self: super: let
13 pyNames = [ "python3" "python36" "python37" "python38" ];
14 overriddenPython = name: [
15 { inherit name; value = super.${name}.override { packageOverrides = self.pythonOverrides; }; }
16 { name = "${name}Packages"; value = self.recurseIntoAttrs self.${name}.pkgs; }
17 ];
18 overriddenPythons = builtins.concatLists (map overriddenPython pyNames);
19 in {
20 pythonOverrides = pyself: pysuper: {};
21 buildPythonOverrides = newOverrides: currentOverrides: super.lib.composeExtensions newOverrides currentOverrides;
22 } // super.lib.attrsets.listToAttrs overriddenPythons;
23
24
25 blivet3 = fromMyPythonPackages "blivet3";
26 buildbot = import ./buildbot.nix;
27 wokkel = fromMyPythonPackages "wokkel";
28 pymilter = fromMyPythonPackages "pymilter";
29}
diff --git a/overlays/sc-im/default.nix b/overlays/sc-im/default.nix
deleted file mode 100644
index f728655..0000000
--- a/overlays/sc-im/default.nix
+++ /dev/null
@@ -1,9 +0,0 @@
1self: super: {
2 sc-im = super.sc-im.overrideAttrs (old: {
3 buildPhase = ''
4 cd src
5 sed -i Makefile -e 's@\...name.info@.local/state/$(name)info@'
6 cd ..
7 '' + old.buildPhase;
8 });
9}
diff --git a/overlays/shaarli/default.nix b/overlays/shaarli/default.nix
deleted file mode 100644
index 3b37ee8..0000000
--- a/overlays/shaarli/default.nix
+++ /dev/null
@@ -1,15 +0,0 @@
1self: super: {
2 shaarli = varDir: super.shaarli.overrideAttrs (old: rec {
3 version = "0.10.2";
4 src = self.fetchurl {
5 url = "https://github.com/shaarli/Shaarli/releases/download/v${version}/shaarli-v${version}-full.tar.gz";
6 sha256 = "0h8sspj7siy3vgpi2i3gdrjcr5935fr4dfwq2zwd70sjx2sh9s78";
7 };
8 patchPhase = "";
9 patches = (old.patches or []) ++ [ ./shaarli_ldap.patch ];
10 installPhase = (old.installPhase or "") + ''
11 cp .htaccess $out/
12 ln -sf ${varDir}/{cache,pagecache,tmp,data} $out/
13 '';
14 });
15}
diff --git a/overlays/shaarli/shaarli_ldap.patch b/overlays/shaarli/shaarli_ldap.patch
deleted file mode 100644
index e66a54f..0000000
--- a/overlays/shaarli/shaarli_ldap.patch
+++ /dev/null
@@ -1,425 +0,0 @@
1commit a19c24edc1057bd411821f9e3e7d1d309d38b1bb
2Author: Ismaël Bouya <ismael.bouya@normalesup.org>
3Date: Sun Feb 3 20:58:18 2019 +0100
4
5 Add ldap connection
6
7diff --git a/.htaccess b/.htaccess
8index 4c00427..5acd708 100644
9--- a/.htaccess
10+++ b/.htaccess
11@@ -6,10 +6,23 @@ RewriteEngine On
12 # Prevent accessing subdirectories not managed by SCM
13 RewriteRule ^(.git|doxygen|vendor) - [F]
14
15+RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
16+RewriteRule ^(.*) - [E=BASE:%1]
17+
18+RewriteCond %{ENV:REDIRECT_BASE} (.+)
19+RewriteRule .* - [E=BASE:%1]
20+
21 # Forward the "Authorization" HTTP header
22 RewriteCond %{HTTP:Authorization} ^(.*)
23 RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
24
25+RewriteCond %{REQUEST_FILENAME} !-f
26+RewriteCond %{REQUEST_FILENAME} !-d
27+RewriteRule ^((?!api/)[^/]*)/?(.*)$ $2?%{QUERY_STRING} [E=USERSPACE:$1]
28+
29+RewriteCond %{ENV:REDIRECT_USERSPACE} (.+)
30+RewriteRule .* - [E=USERSPACE:%1]
31+
32 # REST API
33 RewriteCond %{REQUEST_FILENAME} !-f
34 RewriteCond %{REQUEST_FILENAME} !-d
35diff --git a/application/ApplicationUtils.php b/application/ApplicationUtils.php
36index 911873a..f21a1ef 100644
37--- a/application/ApplicationUtils.php
38+++ b/application/ApplicationUtils.php
39@@ -191,6 +191,9 @@ public static function checkResourcePermissions($conf)
40 $conf->get('resource.page_cache'),
41 $conf->get('resource.raintpl_tmp'),
42 ) as $path) {
43+ if (! is_dir($path)) {
44+ mkdir($path, 0755, true);
45+ }
46 if (! is_readable(realpath($path))) {
47 $errors[] = '"'.$path.'" '. t('directory is not readable');
48 }
49diff --git a/application/config/ConfigManager.php b/application/config/ConfigManager.php
50index 32aaea4..99efc15 100644
51--- a/application/config/ConfigManager.php
52+++ b/application/config/ConfigManager.php
53@@ -21,6 +21,11 @@ class ConfigManager
54
55 public static $DEFAULT_PLUGINS = array('qrcode');
56
57+ /**
58+ * @var string User space.
59+ */
60+ protected $userSpace;
61+
62 /**
63 * @var string Config folder.
64 */
65@@ -41,12 +46,36 @@ class ConfigManager
66 *
67 * @param string $configFile Configuration file path without extension.
68 */
69- public function __construct($configFile = 'data/config')
70+ public function __construct($configFile = null, $userSpace = null)
71 {
72- $this->configFile = $configFile;
73+ $this->userSpace = $this->findLDAPUser($userSpace);
74+ if ($configFile !== null) {
75+ $this->configFile = $configFile;
76+ } else {
77+ $this->configFile = ($this->userSpace === null) ? 'data/config' : 'data/' . $this->userSpace . '/config';
78+ }
79 $this->initialize();
80 }
81
82+ public function findLDAPUser($login, $password = null) {
83+ $connect = ldap_connect(getenv('SHAARLI_LDAP_HOST'));
84+ ldap_set_option($connect, LDAP_OPT_PROTOCOL_VERSION, 3);
85+ if (!$connect || !ldap_bind($connect, getenv('SHAARLI_LDAP_DN'), getenv('SHAARLI_LDAP_PASSWORD'))) {
86+ return false;
87+ }
88+
89+ $search_query = str_replace('%login%', ldap_escape($login), getenv('SHAARLI_LDAP_FILTER'));
90+
91+ $search = ldap_search($connect, getenv('SHAARLI_LDAP_BASE'), $search_query);
92+ $info = ldap_get_entries($connect, $search);
93+
94+ if (ldap_count_entries($connect, $search) == 1 && (is_null($password) || ldap_bind($connect, $info[0]["dn"], $password))) {
95+ return $login;
96+ } else {
97+ return null;
98+ }
99+ }
100+
101 /**
102 * Reset the ConfigManager instance.
103 */
104@@ -269,6 +298,16 @@ public function getConfigFileExt()
105 return $this->configFile . $this->configIO->getExtension();
106 }
107
108+ /**
109+ * Get the current userspace.
110+ *
111+ * @return mixed User space.
112+ */
113+ public function getUserSpace()
114+ {
115+ return $this->userSpace;
116+ }
117+
118 /**
119 * Recursive function which find asked setting in the loaded config.
120 *
121@@ -342,19 +381,31 @@ protected static function removeConfig($settings, &$conf)
122 */
123 protected function setDefaultValues()
124 {
125- $this->setEmpty('resource.data_dir', 'data');
126- $this->setEmpty('resource.config', 'data/config.php');
127- $this->setEmpty('resource.datastore', 'data/datastore.php');
128- $this->setEmpty('resource.ban_file', 'data/ipbans.php');
129- $this->setEmpty('resource.updates', 'data/updates.txt');
130- $this->setEmpty('resource.log', 'data/log.txt');
131- $this->setEmpty('resource.update_check', 'data/lastupdatecheck.txt');
132- $this->setEmpty('resource.history', 'data/history.php');
133+ if ($this->userSpace === null) {
134+ $data = 'data';
135+ $tmp = 'tmp';
136+ $cache = 'cache';
137+ $pagecache = 'pagecache';
138+ } else {
139+ $data = 'data/' . ($this->userSpace);
140+ $tmp = 'tmp/' . ($this->userSpace);
141+ $cache = 'cache/' . ($this->userSpace);
142+ $pagecache = 'pagecache/' . ($this->userSpace);
143+ }
144+
145+ $this->setEmpty('resource.data_dir', $data);
146+ $this->setEmpty('resource.config', $data . '/config.php');
147+ $this->setEmpty('resource.datastore', $data . '/datastore.php');
148+ $this->setEmpty('resource.ban_file', $data . '/ipbans.php');
149+ $this->setEmpty('resource.updates', $data . '/updates.txt');
150+ $this->setEmpty('resource.log', $data . '/log.txt');
151+ $this->setEmpty('resource.update_check', $data . '/lastupdatecheck.txt');
152+ $this->setEmpty('resource.history', $data . '/history.php');
153 $this->setEmpty('resource.raintpl_tpl', 'tpl/');
154 $this->setEmpty('resource.theme', 'default');
155- $this->setEmpty('resource.raintpl_tmp', 'tmp/');
156- $this->setEmpty('resource.thumbnails_cache', 'cache');
157- $this->setEmpty('resource.page_cache', 'pagecache');
158+ $this->setEmpty('resource.raintpl_tmp', $tmp);
159+ $this->setEmpty('resource.thumbnails_cache', $cache);
160+ $this->setEmpty('resource.page_cache', $pagecache);
161
162 $this->setEmpty('security.ban_after', 4);
163 $this->setEmpty('security.ban_duration', 1800);
164diff --git a/application/security/LoginManager.php b/application/security/LoginManager.php
165index d6784d6..bdfaca7 100644
166--- a/application/security/LoginManager.php
167+++ b/application/security/LoginManager.php
168@@ -32,6 +32,9 @@ class LoginManager
169 /** @var string User sign-in token depending on remote IP and credentials */
170 protected $staySignedInToken = '';
171
172+ protected $lastErrorReason = '';
173+ protected $lastErrorIsBanishable = false;
174+
175 /**
176 * Constructor
177 *
178@@ -83,7 +86,7 @@ public function getStaySignedInToken()
179 */
180 public function checkLoginState($cookie, $clientIpId)
181 {
182- if (! $this->configManager->exists('credentials.login')) {
183+ if (! $this->configManager->exists('credentials.login') || (isset($_SESSION['username']) && $_SESSION['username'] && $this->configManager->get('credentials.login') !== $_SESSION['username'])) {
184 // Shaarli is not configured yet
185 $this->isLoggedIn = false;
186 return;
187@@ -133,20 +136,40 @@ public function isLoggedIn()
188 */
189 public function checkCredentials($remoteIp, $clientIpId, $login, $password)
190 {
191- $hash = sha1($password . $login . $this->configManager->get('credentials.salt'));
192+ $this->lastErrorIsBanishable = false;
193+
194+ if ($this->configManager->getUserSpace() !== null && $this->configManager->getUserSpace() !== $login) {
195+ logm($this->configManager->get('resource.log'),
196+ $remoteIp,
197+ 'Trying to login to wrong user space');
198+ $this->lastErrorReason = 'You’re trying to access the wrong account.';
199+ return false;
200+ }
201
202- if ($login != $this->configManager->get('credentials.login')
203- || $hash != $this->configManager->get('credentials.hash')
204- ) {
205+ logm($this->configManager->get('resource.log'),
206+ $remoteIp,
207+ 'Trying LDAP connection');
208+ $result = $this->configManager->findLDAPUser($login, $password);
209+ if ($result === false) {
210 logm(
211 $this->configManager->get('resource.log'),
212 $remoteIp,
213- 'Login failed for user ' . $login
214+ 'Impossible to connect to LDAP'
215 );
216+ $this->lastErrorReason = 'Server error.';
217+ return false;
218+ } else if (is_null($result)) {
219+ logm(
220+ $this->configManager->get('resource.log'),
221+ $remoteIp,
222+ 'Login failed for user ' . $login
223+ );
224+ $this->lastErrorIsBanishable = true;
225+ $this->lastErrorReason = 'Wrong login/password.';
226 return false;
227 }
228
229- $this->sessionManager->storeLoginInfo($clientIpId);
230+ $this->sessionManager->storeLoginInfo($clientIpId, $login);
231 logm(
232 $this->configManager->get('resource.log'),
233 $remoteIp,
234@@ -187,6 +210,10 @@ protected function writeBanFile()
235 */
236 public function handleFailedLogin($server)
237 {
238+ if (!$this->lastErrorIsBanishable) {
239+ return $this->lastErrorReason ?: 'Error during login.';
240+ };
241+
242 $ip = $server['REMOTE_ADDR'];
243 $trusted = $this->configManager->get('security.trusted_proxies', []);
244
245@@ -215,6 +242,7 @@ public function handleFailedLogin($server)
246 );
247 }
248 $this->writeBanFile();
249+ return $this->lastErrorReason ?: 'Error during login.';
250 }
251
252 /**
253diff --git a/application/security/SessionManager.php b/application/security/SessionManager.php
254index b8b8ab8..5eb4aac 100644
255--- a/application/security/SessionManager.php
256+++ b/application/security/SessionManager.php
257@@ -111,10 +111,10 @@ public static function checkId($sessionId)
258 *
259 * @param string $clientIpId Client IP address identifier
260 */
261- public function storeLoginInfo($clientIpId)
262+ public function storeLoginInfo($clientIpId, $login = null)
263 {
264 $this->session['ip'] = $clientIpId;
265- $this->session['username'] = $this->conf->get('credentials.login');
266+ $this->session['username'] = $login ?: $this->conf->get('credentials.login');
267 $this->extendTimeValidityBy(self::$SHORT_TIMEOUT);
268 }
269
270diff --git a/index.php b/index.php
271index 4b86a3e..58ae2dd 100644
272--- a/index.php
273+++ b/index.php
274@@ -121,7 +121,32 @@
275 $_COOKIE['shaarli'] = session_id();
276 }
277
278-$conf = new ConfigManager();
279+$folderBase = getenv("BASE");
280+
281+if (getenv("USERSPACE")) {
282+ if (isset($_GET["do"]) && $_GET["do"] == "login") {
283+ header("Location: $folderBase/?do=login");
284+ exit;
285+ }
286+ $userspace = preg_replace("/[^-_A-Za-z0-9]/", '', getenv("USERSPACE"));
287+} else if (isset($_SESSION["username"]) && $_SESSION["username"]) {
288+ header("Location: " . $folderBase . "/" . $_SESSION["username"] . "?");
289+ exit;
290+} else if (!isset($_GET["do"]) || $_GET["do"] != "login") {
291+ header("Location: $folderBase/?do=login");
292+ exit;
293+}
294+
295+if (!isset($userspace) && isset($_POST["login"])) {
296+ $userspace = preg_replace("/[^-_A-Za-z0-9]/", '', $_POST["login"]);
297+ error_log("debugImmae: setting userspace from POST: " . $userspace);
298+}
299+
300+if (isset($userspace)) {
301+ $conf = new ConfigManager(null, $userspace);
302+} else {
303+ $conf = new ConfigManager();
304+}
305 $sessionManager = new SessionManager($_SESSION, $conf);
306 $loginManager = new LoginManager($GLOBALS, $conf, $sessionManager);
307 $loginManager->generateStaySignedInToken($_SERVER['REMOTE_ADDR']);
308@@ -175,7 +200,7 @@
309 }
310
311 // Display the installation form if no existing config is found
312- install($conf, $sessionManager, $loginManager);
313+ install($conf, $sessionManager, $loginManager, $userspace);
314 }
315
316 $loginManager->checkLoginState($_COOKIE, $clientIpId);
317@@ -205,6 +230,7 @@ function isLoggedIn()
318 && $loginManager->checkCredentials($_SERVER['REMOTE_ADDR'], $clientIpId, $_POST['login'], $_POST['password'])
319 ) {
320 $loginManager->handleSuccessfulLogin($_SERVER);
321+ $userspace = $_POST['login'];
322
323 $cookiedir = '';
324 if (dirname($_SERVER['SCRIPT_NAME']) != '/') {
325@@ -241,25 +267,25 @@ function isLoggedIn()
326 $uri .= '&'.$param.'='.urlencode($_GET[$param]);
327 }
328 }
329- header('Location: '. $uri);
330+ header('Location: '. $userspace . $uri);
331 exit;
332 }
333
334 if (isset($_GET['edit_link'])) {
335- header('Location: ?edit_link='. escape($_GET['edit_link']));
336+ header('Location: ' . $userspace . '?edit_link='. escape($_GET['edit_link']));
337 exit;
338 }
339
340 if (isset($_POST['returnurl'])) {
341 // Prevent loops over login screen.
342 if (strpos($_POST['returnurl'], 'do=login') === false) {
343- header('Location: '. generateLocation($_POST['returnurl'], $_SERVER['HTTP_HOST']));
344+ header('Location: ' . generateLocation($_POST['returnurl'], $_SERVER['HTTP_HOST']));
345 exit;
346 }
347 }
348- header('Location: ?'); exit;
349+ header('Location: '. $userspace . '?'); exit;
350 } else {
351- $loginManager->handleFailedLogin($_SERVER);
352+ $errorReason = $loginManager->handleFailedLogin($_SERVER);
353 $redir = '&username='. urlencode($_POST['login']);
354 if (isset($_GET['post'])) {
355 $redir .= '&post=' . urlencode($_GET['post']);
356@@ -270,7 +296,7 @@ function isLoggedIn()
357 }
358 }
359 // Redirect to login screen.
360- echo '<script>alert("'. t("Wrong login/password.") .'");document.location=\'?do=login'.$redir.'\';</script>';
361+ echo '<script>alert("'. t($errorReason) .'");document.location=\'?do=login'.$redir.'\';</script>';
362 exit;
363 }
364 }
365@@ -1719,7 +1745,7 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager)
366 * @param SessionManager $sessionManager SessionManager instance
367 * @param LoginManager $loginManager LoginManager instance
368 */
369-function install($conf, $sessionManager, $loginManager) {
370+function install($conf, $sessionManager, $loginManager, $userspace) {
371 // On free.fr host, make sure the /sessions directory exists, otherwise login will not work.
372 if (endsWith($_SERVER['HTTP_HOST'],'.free.fr') && !is_dir($_SERVER['DOCUMENT_ROOT'].'/sessions')) mkdir($_SERVER['DOCUMENT_ROOT'].'/sessions',0705);
373
374@@ -1755,7 +1781,7 @@ function install($conf, $sessionManager, $loginManager) {
375 }
376
377
378- if (!empty($_POST['setlogin']) && !empty($_POST['setpassword']))
379+ if (true)
380 {
381 $tz = 'UTC';
382 if (!empty($_POST['continent']) && !empty($_POST['city'])
383@@ -1764,15 +1790,15 @@ function install($conf, $sessionManager, $loginManager) {
384 $tz = $_POST['continent'].'/'.$_POST['city'];
385 }
386 $conf->set('general.timezone', $tz);
387- $login = $_POST['setlogin'];
388- $conf->set('credentials.login', $login);
389+ $conf->set('credentials.login', $userspace);
390 $salt = sha1(uniqid('', true) .'_'. mt_rand());
391 $conf->set('credentials.salt', $salt);
392- $conf->set('credentials.hash', sha1($_POST['setpassword'] . $login . $salt));
393+ $hash = sha1(uniqid('', true) .'_'. mt_rand());
394+ $conf->set('credentials.hash', $hash);
395 if (!empty($_POST['title'])) {
396 $conf->set('general.title', escape($_POST['title']));
397 } else {
398- $conf->set('general.title', 'Shared links on '.escape(index_url($_SERVER)));
399+ $conf->set('general.title', ucwords(str_replace("_", " ", $userspace)));
400 }
401 $conf->set('translation.language', escape($_POST['language']));
402 $conf->set('updates.check_updates', !empty($_POST['updateCheck']));
403@@ -1841,7 +1867,12 @@ function install($conf, $sessionManager, $loginManager) {
404 $app = new \Slim\App($container);
405
406 // REST API routes
407-$app->group('/api/v1', function() {
408+if (isset($userspace)) {
409+ $mountpoint = '/' . $userspace . '/api/v1';
410+} else {
411+ $mountpoint = '/api/v1';
412+}
413+$app->group($mountpoint, function() {
414 $this->get('/info', '\Shaarli\Api\Controllers\Info:getInfo')->setName('getInfo');
415 $this->get('/links', '\Shaarli\Api\Controllers\Links:getLinks')->setName('getLinks');
416 $this->get('/links/{id:[\d]+}', '\Shaarli\Api\Controllers\Links:getLink')->setName('getLink');
417@@ -1860,7 +1891,7 @@ function install($conf, $sessionManager, $loginManager) {
418 $response = $app->run(true);
419 // Hack to make Slim and Shaarli router work together:
420 // If a Slim route isn't found and NOT API call, we call renderPage().
421-if ($response->getStatusCode() == 404 && strpos($_SERVER['REQUEST_URI'], '/api/v1') === false) {
422+if ($response->getStatusCode() == 404 && strpos($_SERVER['REQUEST_URI'], $mountpoint) === false) {
423 // We use UTF-8 for proper international characters handling.
424 header('Content-Type: text/html; charset=utf-8');
425 renderPage($conf, $pluginManager, $linkDb, $history, $sessionManager, $loginManager);
diff --git a/overlays/slrn/default.nix b/overlays/slrn/default.nix
deleted file mode 100644
index 1bf5fe2..0000000
--- a/overlays/slrn/default.nix
+++ /dev/null
@@ -1,5 +0,0 @@
1self: super: {
2 slrn = super.slrn.overrideAttrs (old: rec {
3 configureFlags = old.configureFlags ++ [ "--with-slrnpull" ];
4 });
5}
diff --git a/overlays/taskwarrior/TW-1778_patch.diff b/overlays/taskwarrior/TW-1778_patch.diff
deleted file mode 100644
index 6d7e376..0000000
--- a/overlays/taskwarrior/TW-1778_patch.diff
+++ /dev/null
@@ -1,12 +0,0 @@
1--- a/src/text.cpp 2016-02-24 23:18:11.000000000 +0100
2+++ b/src/text.cpp 2020-02-26 18:53:15.869331031 +0100
3@@ -248,7 +248,7 @@
4 // Premature EOL.
5 if (character == '\n')
6 {
7- line = text.substr (offset, line_length);
8+ line = text.substr (offset, prior_cursor-offset);
9 offset = cursor;
10 return true;
11 }
12
diff --git a/overlays/taskwarrior/default.nix b/overlays/taskwarrior/default.nix
deleted file mode 100644
index 9ca52b8..0000000
--- a/overlays/taskwarrior/default.nix
+++ /dev/null
@@ -1,16 +0,0 @@
1self: super:
2{
3 taskwarrior = super.taskwarrior.overrideAttrs (old: {
4 patches = old.patches or [] ++ [
5 ./TW-1778_patch.diff
6 ];
7 postInstall = ''${old.postInstall}
8 mkdir -p "$out/share/vim/vimfiles/ftdetect"
9 mkdir -p "$out/share/vim/vimfiles/syntax"
10 ln -s "../../../../share/doc/task/scripts/vim/ftdetect/task.vim" "$out/share/vim/vimfiles/ftdetect/"
11 ln -s "../../../../share/doc/task/scripts/vim/syntax/taskrc.vim" "$out/share/vim/vimfiles/syntax/"
12 ln -s "../../../../share/doc/task/scripts/vim/syntax/taskdata.vim" "$out/share/vim/vimfiles/syntax/"
13 ln -s "../../../../share/doc/task/scripts/vim/syntax/taskedit.vim" "$out/share/vim/vimfiles/syntax/"
14 '';
15 });
16}
diff --git a/overlays/vcsh/default.nix b/overlays/vcsh/default.nix
deleted file mode 100644
index eb4d48e..0000000
--- a/overlays/vcsh/default.nix
+++ /dev/null
@@ -1,7 +0,0 @@
1self: super: {
2 vcsh = super.vcsh.overrideAttrs(old: {
3 patchPhase = old.patchPhase or "" + ''
4 sed -i -e 's@-r "$XDG_CONFIG_HOME/vcsh/config.d/$VCSH_REPO_NAME"@-f "$XDG_CONFIG_HOME/vcsh/config.d/$VCSH_REPO_NAME"@' vcsh
5 '';
6 });
7}
diff --git a/overlays/weechat/default.nix b/overlays/weechat/default.nix
deleted file mode 100644
index e8cc792..0000000
--- a/overlays/weechat/default.nix
+++ /dev/null
@@ -1,12 +0,0 @@
1self: super: {
2 weechat = super.weechat.override {
3 configure = { availablePlugins, ... }: {
4 plugins = with self; with availablePlugins; [
5 (python.withPackages (ps: with ps; [websocket_client emoji]))
6 perl
7 ruby
8 ];
9 };
10 };
11
12}
diff --git a/overlays/ympd/default.nix b/overlays/ympd/default.nix
deleted file mode 100644
index dda17aa..0000000
--- a/overlays/ympd/default.nix
+++ /dev/null
@@ -1,5 +0,0 @@
1self: super: {
2 ympd = super.ympd.overrideAttrs(old: self.mylibs.fetchedGithub ./ympd.json // {
3 patches = (old.patches or []) ++ [ ./ympd-password-env.patch ];
4 });
5}
diff --git a/overlays/ympd/ympd-password-env.patch b/overlays/ympd/ympd-password-env.patch
deleted file mode 100644
index 2bbe188..0000000
--- a/overlays/ympd/ympd-password-env.patch
+++ /dev/null
@@ -1,23 +0,0 @@
1diff --git a/src/ympd.c b/src/ympd.c
2index 3aed7e6..b3b6fda 100644
3--- a/src/ympd.c
4+++ b/src/ympd.c
5@@ -71,6 +71,7 @@ int main(int argc, char **argv)
6 char *run_as_user = NULL;
7 char const *error_msg = NULL;
8 char *webport = "8080";
9+ const char *s;
10
11 atexit(bye);
12 #ifdef WITH_DYNAMIC_ASSETS
13@@ -92,6 +93,10 @@ int main(int argc, char **argv)
14 {0, 0, 0, 0 }
15 };
16
17+ if ((s = getenv("MPD_PASSWORD")) != NULL) {
18+ mpd.password = strdup(s);
19+ }
20+
21 while((n = getopt_long(argc, argv, "h:p:w:u:vm:",
22 long_options, &option_index)) != -1) {
23 switch (n) {
diff --git a/overlays/ympd/ympd.json b/overlays/ympd/ympd.json
deleted file mode 100644
index 51f06d5..0000000
--- a/overlays/ympd/ympd.json
+++ /dev/null
@@ -1,15 +0,0 @@
1{
2 "tag": "612f8fc-master",
3 "meta": {
4 "name": "ympd",
5 "url": "https://github.com/notandy/ympd",
6 "branch": "master"
7 },
8 "github": {
9 "owner": "notandy",
10 "repo": "ympd",
11 "rev": "612f8fc0b2c47fc89d403e4a044541c6b2b238c8",
12 "sha256": "01hnj10zl103mrn82vyd42fvq7w5az3jf1qz18889zv67kn73ll9",
13 "fetchSubmodules": true
14 }
15}