1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.firefox.syncserver;
7 syncServerIni = pkgs.writeText "syncserver.ini" ''
8 [DEFAULT]
9 overrides = ${cfg.privateConfig}
10
11 [server:main]
12 use = egg:Paste#http
13 host = ${cfg.listen.address}
14 port = ${toString cfg.listen.port}
15
16 [app:main]
17 use = egg:syncserver
18
19 [syncserver]
20 public_url = ${cfg.publicUrl}
21 ${optionalString (cfg.sqlUri != "") "sqluri = ${cfg.sqlUri}"}
22 allow_new_users = ${if cfg.allowNewUsers then "true" else "false"}
23
24 [browserid]
25 backend = tokenserver.verifiers.LocalVerifier
26 audiences = ${removeSuffix "/" cfg.publicUrl}
27 '';
28in
29
30{
31 options = {
32 services.firefox.syncserver = {
33 enable = mkOption {
34 type = types.bool;
35 default = false;
36 example = true;
37 description = ''
38 Whether to enable a Firefox Sync Server, this give the opportunity to
39 Firefox users to store all synchronized data on their own server. To use this
40 server, Firefox users should visit the <option>about:config</option>, and
41 replicate the following change
42
43 <screen>
44 services.sync.tokenServerURI: http://localhost:5000/token/1.0/sync/1.5
45 </screen>
46
47 where <option>http://localhost:5000/</option> corresponds to the
48 public url of the server.
49 '';
50 };
51
52 listen.address = mkOption {
53 type = types.str;
54 default = "127.0.0.1";
55 example = "0.0.0.0";
56 description = ''
57 Address on which the sync server listen to.
58 '';
59 };
60
61 listen.port = mkOption {
62 type = types.int;
63 default = 5000;
64 description = ''
65 Port on which the sync server listen to.
66 '';
67 };
68
69 publicUrl = mkOption {
70 type = types.str;
71 default = "http://localhost:5000/";
72 example = "http://sync.example.com/";
73 description = ''
74 Public URL with which firefox users can use to access the sync server.
75 '';
76 };
77
78 allowNewUsers = mkOption {
79 type = types.bool;
80 default = true;
81 example = false;
82 description = ''
83 Whether to allow new-user signups on the server. Only request by
84 existing accounts will be honored.
85 '';
86 };
87
88 sqlUri = mkOption {
89 type = types.str;
90 default = "sqlite:////var/db/firefox-sync-server.db";
91 example = "postgresql://scott:tiger@localhost/test";
92 description = ''
93 The location of the database. This URL is composed of
94 <option>dialect[+driver]://user:password@host/dbname[?key=value..]</option>,
95 where <option>dialect</option> is a database name such as
96 <option>mysql</option>, <option>oracle</option>, <option>postgresql</option>,
97 etc., and <option>driver</option> the name of a DBAPI, such as
98 <option>psycopg2</option>, <option>pyodbc</option>, <option>cx_oracle</option>,
99 etc. The <link
100 xlink:href="http://docs.sqlalchemy.org/en/rel_0_9/core/engines.html#database-urls">
101 SQLAlchemy documentation</link> provides more examples and describe the syntax of
102 the expected URL.
103 '';
104 };
105
106 privateConfig = mkOption {
107 type = types.str;
108 default = "/etc/firefox/syncserver-secret.ini";
109 description = ''
110 The private config file is used to extend the generated config with confidential
111 information, such as the <option>syncserver.sqlUri</option> setting if it contains a
112 password, and the <option>syncserver.secret</option> setting is used by the server to
113 generate cryptographically-signed authentication tokens.
114
115 If this file does not exists, then it is created with a generated
116 <option>syncserver.secret</option> settings.
117 '';
118 };
119 };
120 };
121
122 config = mkIf cfg.enable {
123
124 systemd.services.syncserver = {
125 after = [ "network.target" ];
126 description = "Firefox Sync Server";
127 wantedBy = [ "multi-user.target" ];
128 path = [ pkgs.pythonPackages.pasteScript pkgs.coreutils ];
129 environment.PYTHONPATH = "${pkgs.pythonPackages.syncserver}/lib/${pkgs.pythonPackages.python.libPrefix}/site-packages";
130 preStart = ''
131 if ! test -e ${cfg.privateConfig}; then
132 umask u=rwx,g=x,o=x
133 mkdir -p $(dirname ${cfg.privateConfig})
134 echo > ${cfg.privateConfig} '[syncserver]'
135 echo >> ${cfg.privateConfig} "secret = $(head -c 20 /dev/urandom | sha1sum | tr -d ' -')"
136 fi
137 '';
138 serviceConfig.ExecStart = "${pkgs.pythonPackages.pasteScript}/bin/paster serve ${syncServerIni}";
139 };
140
141 };
142}