1 /**
2  * Orthanc - A Lightweight, RESTful DICOM Store
3  * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4  * Department, University Hospital of Liege, Belgium
5  * Copyright (C) 2017-2021 Osimis S.A., Belgium
6  *
7  * This program is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU Affero General Public License
9  * as published by the Free Software Foundation, either version 3 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  **/
20 
21 
22 #include "PostgreSQLParameters.h"
23 
24 #include <Logging.h>
25 #include <OrthancException.h>
26 
27 #include <boost/lexical_cast.hpp>
28 
29 
30 namespace OrthancDatabases
31 {
Reset()32   void PostgreSQLParameters::Reset()
33   {
34     host_ = "localhost";
35     port_ = 5432;
36     username_ = "";
37     password_ = "";
38     database_.clear();
39     uri_.clear();
40     ssl_ = false;
41     lock_ = true;
42     maxConnectionRetries_ = 10;
43     connectionRetryInterval_ = 5;
44   }
45 
46 
PostgreSQLParameters()47   PostgreSQLParameters::PostgreSQLParameters()
48   {
49     Reset();
50   }
51 
52 
PostgreSQLParameters(const OrthancPlugins::OrthancConfiguration & configuration)53   PostgreSQLParameters::PostgreSQLParameters(const OrthancPlugins::OrthancConfiguration& configuration)
54   {
55     Reset();
56 
57     std::string s;
58 
59     if (configuration.LookupStringValue(s, "ConnectionUri"))
60     {
61       SetConnectionUri(s);
62     }
63     else
64     {
65       if (configuration.LookupStringValue(s, "Host"))
66       {
67         SetHost(s);
68       }
69 
70       unsigned int port;
71       if (configuration.LookupUnsignedIntegerValue(port, "Port"))
72       {
73         SetPortNumber(port);
74       }
75 
76       if (configuration.LookupStringValue(s, "Database"))
77       {
78         SetDatabase(s);
79       }
80 
81       if (configuration.LookupStringValue(s, "Username"))
82       {
83         SetUsername(s);
84       }
85 
86       if (configuration.LookupStringValue(s, "Password"))
87       {
88         SetPassword(s);
89       }
90 
91       ssl_ = configuration.GetBooleanValue("EnableSsl", false);
92     }
93 
94     lock_ = configuration.GetBooleanValue("Lock", true);  // Use locking by default
95 
96     maxConnectionRetries_ = configuration.GetUnsignedIntegerValue("MaximumConnectionRetries", 10);
97     connectionRetryInterval_ = configuration.GetUnsignedIntegerValue("ConnectionRetryInterval", 5);
98   }
99 
100 
SetConnectionUri(const std::string & uri)101   void PostgreSQLParameters::SetConnectionUri(const std::string& uri)
102   {
103     uri_ = uri;
104   }
105 
106 
GetConnectionUri() const107   std::string PostgreSQLParameters::GetConnectionUri() const
108   {
109     if (uri_.empty())
110     {
111       std::string actualUri = "postgresql://";
112 
113       if (!username_.empty())
114       {
115         actualUri += username_;
116 
117         if (!password_.empty())
118         {
119           actualUri += ":" + password_;
120         }
121 
122         actualUri += "@" + host_;
123       }
124       else
125       {
126         actualUri += host_;
127       }
128 
129       if (port_ > 0)
130       {
131         actualUri += ":" + boost::lexical_cast<std::string>(port_);
132       }
133 
134       actualUri += "/" + database_;
135 
136       return actualUri;
137     }
138     else
139     {
140       return uri_;
141     }
142   }
143 
144 
SetHost(const std::string & host)145   void PostgreSQLParameters::SetHost(const std::string& host)
146   {
147     uri_.clear();
148     host_ = host;
149   }
150 
SetPortNumber(unsigned int port)151   void PostgreSQLParameters::SetPortNumber(unsigned int port)
152   {
153     if (port == 0 ||
154         port >= 65535)
155     {
156       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
157     }
158 
159     uri_.clear();
160     port_ = port;
161   }
162 
SetUsername(const std::string & username)163   void PostgreSQLParameters::SetUsername(const std::string& username)
164   {
165     uri_.clear();
166     username_ = username;
167   }
168 
SetPassword(const std::string & password)169   void PostgreSQLParameters::SetPassword(const std::string& password)
170   {
171     uri_.clear();
172     password_ = password;
173   }
174 
SetDatabase(const std::string & database)175   void PostgreSQLParameters::SetDatabase(const std::string& database)
176   {
177     uri_.clear();
178     database_ = database;
179   }
180 
Format(std::string & target) const181   void PostgreSQLParameters::Format(std::string& target) const
182   {
183     if (uri_.empty())
184     {
185       // Note about SSL: "require" means that "I want my data to be
186       // encrypted, and I accept the overhead. I trust that the
187       // network will make sure I always connect to the server I want."
188       // https://www.postgresql.org/docs/current/libpq-ssl.html
189       target = std::string(ssl_ ? "sslmode=require" : "sslmode=disable") +
190         " user=" + username_ +
191         " host=" + host_ +
192         " port=" + boost::lexical_cast<std::string>(port_);
193 
194       if (!password_.empty())
195       {
196         target += " password=" + password_;
197       }
198 
199       if (database_.size() > 0)
200       {
201         target += " dbname=" + database_;
202       }
203     }
204     else
205     {
206       target = uri_;
207     }
208   }
209 }
210