-
Notifications
You must be signed in to change notification settings - Fork 28
/
rsinit.h
510 lines (430 loc) · 19.8 KB
/
rsinit.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
/*******************************************************************************
* libretroshare/src/retroshare: rsinit.h *
* *
* Copyright (C) 2004-2014 Robert Fernie <[email protected]> *
* Copyright (C) 2016-2019 Gioacchino Mazzurco <[email protected]> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#pragma once
/// @file RetroShare initialization and login API
// Initialize ok, result >= 0
#define RS_INIT_OK 0 // Initialize ok
#define RS_INIT_HAVE_ACCOUNT 1 // Initialize ok, have account
// Initialize failed, result < 0
#define RS_INIT_AUTH_FAILED -1 // AuthGPG::InitAuth failed
#define RS_INIT_BASE_DIR_ERROR -2 // AuthGPG::InitAuth failed
#define RS_INIT_NO_KEYRING -3 // Keyring is empty. Need to import it.
#define RS_INIT_NO_EXECUTABLE -4 // executable path hasn't been set in config options
#include <list>
#include <map>
#include <vector>
#include <cstdint>
#include <system_error>
#include "retroshare/rstypes.h"
#include "retroshare/rsversion.h"
class RsLoginHelper;
/**
* Pointer to global instance of RsLoginHelper
* @jsonapi{development}
*/
extern RsLoginHelper* rsLoginHelper;
enum class RsInitErrorNum : int32_t
{
ALREADY_LOGGED_IN = 6000,
CANT_ACQUIRE_LOCK = 6001,
INVALID_LOCATION_NAME = 6002,
PGP_NAME_OR_ID_NEEDED = 6003,
PGP_KEY_CREATION_FAILED = 6004,
SSL_KEY_CREATION_FAILED = 6005,
INVALID_SSL_ID = 6006,
LOGIN_FAILED = 6007
};
struct RsInitErrorCategory: std::error_category
{
const char* name() const noexcept override
{ return "RetroShare init"; }
std::string message(int ev) const override
{
switch (static_cast<RsInitErrorNum>(ev))
{
case RsInitErrorNum::ALREADY_LOGGED_IN:
return "Already logged in";
case RsInitErrorNum::CANT_ACQUIRE_LOCK:
return "Cannot aquire lock on location data. Another instance is "
"already running with this profile?";
case RsInitErrorNum::INVALID_LOCATION_NAME:
return "Invalid location name";
case RsInitErrorNum::PGP_NAME_OR_ID_NEEDED:
return "Either PGP name or PGP id is needed";
case RsInitErrorNum::PGP_KEY_CREATION_FAILED:
return "Failure creating PGP key";
case RsInitErrorNum::SSL_KEY_CREATION_FAILED:
return "Failure creating SSL key";
case RsInitErrorNum::INVALID_SSL_ID:
return "Invalid SSL id";
case RsInitErrorNum::LOGIN_FAILED:
return "Generic login failure";
default:
return rsErrorNotInCategory(ev, name());
}
}
const static RsInitErrorCategory instance;
};
namespace std
{
/** Register RsJsonApiErrorNum as an error condition enum, must be in std
* namespace */
template<> struct is_error_condition_enum<RsInitErrorNum> : true_type {};
}
/** Provide RsInitErrorNum conversion to std::error_condition, must be in
* same namespace of RsInitErrorNum */
inline std::error_condition make_error_condition(RsInitErrorNum e) noexcept
{
return std::error_condition(
static_cast<int>(e), RsInitErrorCategory::instance );
};
/**
* @brief The RsInitConfig struct
* This class contains common configuration options, that executables using libretroshare may want to
* set using e.g. commandline options. To be passed to RsInit::InitRetroShare().
*/
struct RsConfigOptions
{
RsConfigOptions();
// required
std::string main_executable_path;/* this should be set to argv[0] */
// Optional. Only change if needed.
bool autoLogin; /* try auto-login */
bool udpListenerOnly; /* only listen to udp */
std::string forcedInetAddress; /* inet address to use.*/
uint16_t forcedPort; /* port to listen to */
bool outStderr;
int debugLevel;
std::string logfname; /* output filename for log */
std::string opModeStr; /* operating mode. Acceptable values: "Full", "NoTurtle", "Gaming", "Minimal" */
std::string optBaseDir; /* base directory where to find profiles, etc */
std::string userSuppliedTorExecutable; /* allows the user to supply his own Tor executable, or to tell RS where to find Tor */
uint16_t jsonApiPort; /* port to use fo Json API */
std::string jsonApiBindAddress; /* bind address for Json API */
bool enableWebUI; /* enable web interface */
std::string webUIPasswd; /* passwd to start the webui with */
};
/*!
* Initialisation Class (not publicly disclosed to RsIFace)
*/
class RsInit
{
public:
enum LoadCertificateStatus : uint8_t
{
OK = 0x00, /// Everything go as expected, no error occurred
ERR_ALREADY_RUNNING = 0x01, /// Another istance is running already
ERR_CANT_ACQUIRE_LOCK = 0x02, /// Another istance is already running?
ERR_NO_AVAILABLE_ACCOUNT = 0x03, /// Used in retroshare-service -U list when no account is available
ERR_CANNOT_CONFIGURE_TOR = 0x04, /// cannot start/configure Tor for an auto-tor node
ERR_NO_ACCOUNT_SELECTED = 0x05, /// cannot start/configure Tor for an auto-tor node
ERR_MISSING_ACCOUNT_PATH = 0x06, /// cannot start/configure Tor for an auto-tor node
ERR_MISSING_PASSPHRASE = 0x07, /// cannot start/configure Tor for an auto-tor node
// Errors directly reported by AuthSSL::InitImpl()
ERR_CERT_CRYPTO_IS_TOO_WEAK = 0x08, /// Certificate is based on some weak settings.
ERR_CANNOT_INIT_TLS_LIB = 0x09, /// TLS initialization failed.
ERR_MISSING_PARAMETERS = 0x0a, /// Some params are null, including public/private cert filenames, and login passwd.
ERR_MISSING_CERT_FILE = 0x0b, /// Missing public key file (user_cert.pem)
ERR_MISSING_PKEY_FILE = 0x0c, /// Missing private key file (user_pk.pem)
ERR_CORRUPTED_CERT_FILE = 0x0d, /// Public node key file is corrupted
ERR_CORRUPTED_PKEY_FILE = 0x0e, /// Private node key file is corrupted
ERR_PUBLIC_PKEY_MISMATCH = 0x0f, /// Public key doesn't match private key. May be due to file corruption between user_pk.pem and user_cert.pem.
ERR_CERT_VALIDATION_FAILED = 0x10, /// Profile signature validation failed on node certificate
ERR_WRONG_CERT_FORMAT = 0x11, /// Certificate format is not recognised (e.g. signature missing, etc)
ERR_CERT_REJECTED_BY_SSL = 0x12, /// Certificate doesn't pass OpenSSL internal checks.
ERR_UNKNOWN = 0xff, /// Unkown error, maybe password is wrong?
};
/* reorganised RsInit system */
/*!
* PreLogin
* Call before init retroshare, initialises rsinitconfig's public attributes
*/
static void InitRsConfig();
/*!
* Should be called to load up ssl cert and private key, and intialises gpg
* this must be called before accessing rsserver (e.g. ::startupretroshare)
* @param argc passed from executable
* @param argv commandline arguments passed to executable
* @param strictCheck set to true if you want rs to continue executing if
* invalid argument passed and vice versa
* @return RS_INIT_...
*/
static int InitRetroShare(const RsConfigOptions&);
#ifdef RS_JSONAPI
static void startupWebServices(const RsConfigOptions& conf, bool force_start_jsonapi);
#endif
static bool isPortable();
static bool isWindowsXP();
static bool collectEntropy(uint32_t bytes) ;
static bool startAutoTor();
/*!
* \brief lockFilePath
* \return
* full path for the lock file. Can be used to warn the user about a non deleted lock that would prevent to start.
*/
static std::string lockFilePath();
/*
* Setup Hidden Location;
*/
static void SetHiddenLocation(const std::string& hiddenaddress, uint16_t port, bool useI2p);
static bool LoadPassword(const std::string& passwd) ;
/*
* Final Certificate load. This can be called if:
* a) InitRetroshare() returns RS_INIT_HAVE_ACCOUNT -> autoLoad/password Set.
* b) or LoadPassword()
*
* This uses the preferredId from RsAccounts.
* This wrapper also locks the profile before finalising the login
*/
static LoadCertificateStatus LockAndLoadCertificates(
bool autoLoginNT, std::string& lockFilePath );
// Post Login Options
static bool getStartMinimised();
static int getSslPwdLen();
static bool getAutoLogin();
static void setAutoLogin(bool autoLogin);
static bool RsClearAutoLogin() ;
static std::string executablePath() ;
private:
/** @brief Lock profile directory
* param[in] accountDir account directory to lock
* param[out] lockFilePath path of the created lock-file
*/
static LoadCertificateStatus LockConfigDirectory(
const std::string& accountDir, std::string& lockFilePath);
/// @brief Unlock profile directory
static void UnlockConfigDirectory();
static bool LoadCertificates(bool autoLoginNT,LoadCertificateStatus& error_code);
};
/* Seperate static Class for dealing with Accounts */
class RsAccountsDetail;
class RsAccounts
{
public:
/// Should be called once before everything else.
static bool init(const std::string &opt_base_dir, int& error_code);
/**
* @brief ConfigDirectory (usually ~/.retroshare) you can call this method
* even before initialisation (you can't with some other methods)
* @see RsAccountsDetail::PathBaseDirectory()
* @jsonapi{development,unauthenticated}
* @return a string containing the path
*/
static std::string ConfigDirectory();
/**
* @brief Get current account id. Beware that an account may be selected
* without actually logging in.
* @jsonapi{development,unauthenticated}
* @param[out] id storage for current account id
* @return false if account hasn't been selected yet, true otherwise
*/
static bool getCurrentAccountId(RsPeerId &id);
/**
* @brief DataDirectory
* you can call this method even before initialisation (you can't with some other methods)
* @param check if set to true and directory does not exist, return empty string
* @return path where global platform independent files are stored, like bdboot.txt or webinterface files
*/
static std::string systemDataDirectory(bool check = true);
static std::string PGPDirectory();
/**
* @brief Get available PGP identities id list
* @jsonapi{development,unauthenticated}
* @param[out] pgpIds storage for PGP id list
* @return true on success, false otherwise
*/
static int GetPGPLogins(std::list<RsPgpId> &pgpIds);
static int GetPGPLoginDetails(const RsPgpId& id, std::string &name, std::string &email);
static bool GeneratePGPCertificate(const std::string&, const std::string& email, const std::string& passwd, RsPgpId &pgpId, const int keynumbits, std::string &errString);
/**
* @brief Export full encrypted PGP identity to file
* @jsonapi{development}
* @param[in] filePath path of certificate file
* @param[in] pgpId PGP id to export
* @return true on success, false otherwise
*/
static bool ExportIdentity( const std::string& filePath,
const RsPgpId& pgpId );
/**
* @brief Import full encrypted PGP identity from file
* @jsonapi{development,unauthenticated}
* @param[in] filePath path of certificate file
* @param[out] pgpId storage for the PGP fingerprint of the imported key
* @param[out] errorMsg storage for eventual human readable error message
* @return true on success, false otherwise
*/
static bool ImportIdentity(
const std::string& filePath, RsPgpId& pgpId, std::string& errorMsg );
/**
* @brief Import full encrypted PGP identity from string
* @jsonapi{development,unauthenticated}
* @param[in] data certificate string
* @param[out] pgpId storage for the PGP fingerprint of the imported key
* @param[out] errorMsg storage for eventual human readable error message
* @return true on success, false otherwise
*/
static bool importIdentityFromString(
const std::string& data, RsPgpId& pgpId,
std::string& errorMsg );
/**
* @brief Export full encrypted PGP identity to string
* @jsonapi{development}
* @param[out] data storage for certificate string
* @param[in] pgpId PGP id to export
* @param[in] includeSignatures true to include signatures
* @param[out] errorMsg storage for eventual human readable error message
* @return true on success, false otherwise
*/
static bool exportIdentityToString(
std::string& data, const RsPgpId& pgpId, std::string& errorMsg,
bool includeSignatures = true );
static void GetUnsupportedKeys(std::map<std::string,std::vector<std::string> > &unsupported_keys);
static bool CopyGnuPGKeyrings() ;
// Rs Accounts
static bool SelectAccount(const RsPeerId& id);
static bool GetPreferredAccountId(RsPeerId &id);
static bool GetAccountIds(std::list<RsPeerId> &ids);
static bool GetAccountDetails(const RsPeerId &id, RsPgpId &gpgId, std::string &gpgName, std::string &gpgEmail, std::string &location);
static bool createNewAccount(
const RsPgpId& pgp_id, const std::string& org,
const std::string& loc, const std::string& country,
bool ishiddenloc, bool is_auto_tor, const std::string& passwd,
RsPeerId &sslId, std::string &errString );
static void storeSelectedAccount() ;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// All methods bellow can only be called ones SelectAccount() as been called. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static bool getCurrentAccountOptions(bool& is_hidden,bool& is_tor_auto,bool& is_first_time) ;
static bool checkCreateAccountDirectory(); // Generate the hierarchy of directories below ~/.retroshare/[SSL dir]/
static bool isHiddenNode() ; // true if the running node is a hidden node. Used to choose which services to start.
static bool isTorAuto() ; // true if the running node is a hidden node using automated Tor management
static std::string AccountDirectory(); // linux: ~/.retroshare/[SSL dir]/
static std::string AccountKeysDirectory(); // linux: ~/.retroshare/[SSL dir]/keys/
static std::string AccountPathCertFile(); // linux: ~/.retroshare/[SSL dir]/keys/user_cert.pem
static std::string AccountPathKeyFile(); // linux: ~/.retroshare/[SSL dir]/keys/user_pk.pem
static std::string AccountLocationName();
static bool lockPreferredAccount() ; // are these methods any useful??
static void unlockPreferredAccount() ;
private:
static RsAccountsDetail* rsAccountsDetails;
};
/**
* Pointer to global instance of RsAccounts needed to expose JSON API, as all
* the members of this class are static you should call them directly without
* using this pointer in the other parts of the code
* @jsonapi{development}
*/
extern RsAccounts* rsAccounts;
/**
* This helper class have been implemented because there was not reasonable way
* to login in the API that could be exposed via JSON API
*/
class RsLoginHelper
{
public:
RsLoginHelper() = default;
/**
* @brief Normal way to attempt login
* @jsonapi{development,unauthenticated}
* @param[in] account Id of the account to which attempt login
* @param[in] password Password for the given account
* @return RsInit::OK if login attempt success, error code otherwhise
*/
RsInit::LoadCertificateStatus attemptLogin(
const RsPeerId& account, const std::string& password );
/**
* @brief Feed extra entropy to the crypto libraries
* @jsonapi{development,unauthenticated}
* @param[in] bytes number to feed to the entropy pool
* @return false if error occurred, true otherwise
*/
static bool collectEntropy(uint32_t bytes);
struct Location : RsSerializable
{
RsPeerId mLocationId;
RsPgpId mPgpId;
std::string mLocationName;
std::string mPgpName;
/// @see RsSerializable::serial_process
void serial_process( RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx );
};
/**
* @brief Get locations and associated information
* @jsonapi{development,unauthenticated}
* @param[out] locations storage for the retrived locations
*/
void getLocations(std::vector<RsLoginHelper::Location>& locations);
/**
* @brief Creates a new RetroShare location, and log in once is created
* @jsonapi{development,manualwrapper}
* @param[out] locationId storage for generated location SSL id
* @param[inout] pgpId specify PGP id to use to sign the location, if a null
* id is passed the PGP key is created too and this param is used as
* storage for its id.
* @param[in] password to protect and unlock the associated PGP key
* param[in] apiUser (JSON API only) string containing username for JSON API
* so it can be later used to authenticate JSON API calls. It is passed
* down to @see RsJsonApi::authorizeUser under the hood.
* param[in] apiPass (JSON API only) string containing password for JSON API
* so it can be later used to authenticate JSON API calls. It is passed
* down to @see RsJsonApi::authorizeUser under the hood.
* To improve security we strongly advise to not use the same as the
* password used for the PGP key.
* @return Success or error information
*/
std::error_condition createLocationV2(
RsPeerId& locationId,
RsPgpId& pgpId,
const std::string& locationName,
const std::string& pgpName,
const std::string& password
/* JSON API only
* const std::string& apiUser
* const std::string& apiPass */ );
/**
* @brief Check if RetroShare is already logged in, this usually return true
* after a successfull attemptLogin() and before closeSession()
* @jsonapi{development,unauthenticated}
* @return true if already logged in, false otherwise
*/
bool isLoggedIn();
#if !RS_VERSION_AT_LEAST(0,6,6)
/**
* @deprecated Use @see createLocationV2 instead
* @brief Creates a new RetroShare location, and log in once is created
* @jsonapi{development,manualwrapper}
* @param[inout] location provide input information to generate the location
* and storage to output the data of the generated location
* @param[in] password to protect and unlock the associated PGP key
* @param[out] errorMessage if some error occurred human readable error
* message
* @param[in] makeHidden pass true to create an hidden location. UNTESTED!
* @param[in] makeAutoTor pass true to create an automatically configured
* Tor hidden location. UNTESTED!
* @return true if success, false otherwise
*/
RS_DEPRECATED_FOR(createLocationV2)
bool createLocation( RsLoginHelper::Location& location,
const std::string& password, std::string& errorMessage,
bool makeHidden = false, bool makeAutoTor = false );
#endif // !RS_VERSION_AT_LEAST(0,6,6)
};