1 /*
2 * RSessionContext.hpp
3 *
4 * Copyright (C) 2021 by RStudio, PBC
5 *
6 * Unless you have received this program directly from RStudio pursuant
7 * to the terms of a commercial license agreement with RStudio, then
8 * this program is licensed to you under the terms of version 3 of the
9 * GNU Affero General Public License. This program is distributed WITHOUT
10 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
11 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
12 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
13 *
14 */
15
16 #ifndef CORE_R_UTIL_R_SESSION_CONTEXT_HPP
17 #define CORE_R_UTIL_R_SESSION_CONTEXT_HPP
18
19 #include <string>
20 #include <vector>
21 #include <sstream>
22 #include <iomanip>
23 #include <iostream>
24
25 #include <boost/function.hpp>
26
27 #define kProjectNone "none"
28 #define kUserIdLen 5
29 #define kProjectIdLen 8
30 #define kProjectNoneId "cfc78a31"
31 #define kJupyterLabId "21f2ed72"
32 #define kJupyterNotebookId "2cb256d2"
33 #define kWorkspacesId "3c286bd3"
34 #define kVSCodeId "3c9ab5a7"
35
36 #define kWorkbenchRStudio "RStudio"
37 #define kWorkbenchJupyterLab "JupyterLab"
38 #define kWorkbenchJupyterNotebook "Jupyter Notebook"
39 #define kWorkbenchVSCode "VS Code"
40
41 #ifdef _WIN32
42 typedef unsigned int uid_t;
geteuid()43 inline uid_t geteuid()
44 {
45 return 0;
46 }
47 #endif
48
49 namespace rstudio {
50 namespace core {
51
52 class FilePath;
53
54 namespace r_util {
55
56 enum SessionScopeState
57 {
58 ScopeValid,
59 ScopeInvalidSession,
60 ScopeInvalidProject,
61 ScopeMissingProject,
62 };
63
64 void setMinUid(uid_t minUid);
65 std::string obfuscatedUserId(uid_t uid);
66
67 class ProjectId
68 {
69 public:
ProjectId()70 ProjectId()
71 {}
72
ProjectId(const std::string & id)73 ProjectId(const std::string &id)
74 {
75 if (id.length() == kProjectIdLen)
76 {
77 id_ = id;
78 userId_ = obfuscatedUserId(::geteuid());
79 }
80 else if (id.length() == (kProjectIdLen + kUserIdLen))
81 {
82 userId_ = id.substr(0, kUserIdLen);
83 id_ = id.substr(kUserIdLen);
84 }
85 }
86
ProjectId(const std::string & id,const std::string & userId)87 ProjectId(const std::string& id, const std::string& userId):
88 id_(id), userId_(userId)
89 {}
90
ProjectId(const std::string & id,uid_t userId)91 ProjectId(const std::string& id, uid_t userId):
92 id_(id)
93 {
94 userId_ = obfuscatedUserId(userId);
95 }
96
asString() const97 std::string asString() const
98 {
99 return userId_ + id_;
100 }
101
operator ==(const ProjectId & other) const102 bool operator==(const ProjectId &other) const
103 {
104 return id_ == other.id_ && userId_ == other.userId_;
105 }
106
operator <(const ProjectId & other) const107 bool operator<(const ProjectId &other) const
108 {
109 return id_ < other.id_ ||
110 (id_ == other.id_ && userId_ < other.userId_);
111 }
112
id() const113 const std::string& id() const
114 {
115 return id_;
116 }
117
userId() const118 const std::string& userId() const
119 {
120 return userId_;
121 }
122
123 private:
124 std::string id_;
125 std::string userId_;
126 };
127
128 typedef boost::function<std::string(const ProjectId&)> ProjectIdToFilePath;
129 typedef boost::function<ProjectId(const std::string&)> FilePathToProjectId;
130
131 class SessionScope
132 {
133 private:
SessionScope(const ProjectId & project,const std::string & id)134 SessionScope(const ProjectId& project, const std::string& id)
135 : project_(project), id_(id)
136 {
137 }
138
139 public:
140
141 static SessionScope fromProject(
142 const std::string& project,
143 const std::string& id,
144 const FilePathToProjectId& filePathToProjectId);
145
146 static std::string projectPathForScope(
147 const SessionScope& scope,
148 const ProjectIdToFilePath& projectIdToFilePath);
149
150 static SessionScope fromProjectId(const ProjectId& project,
151 const std::string& id);
152
153 static SessionScope projectNone(const std::string& id);
154
155 static SessionScope jupyterLabSession(const std::string& id);
156 static SessionScope jupyterNotebookSession(const std::string& id);
157
158 static SessionScope vscodeSession(const std::string& id);
159
SessionScope()160 SessionScope()
161 {
162 }
163
164 bool isProjectNone() const;
165
166 bool isWorkspaces() const;
167
168 bool isJupyter() const;
169 bool isJupyterLab() const;
170 bool isJupyterNotebook() const;
171 bool isVSCode() const;
172
173 std::string workbench() const;
174
project() const175 const std::string project() const { return project_.asString(); }
176
id() const177 const std::string& id() const { return id_; }
178
projectId() const179 const ProjectId& projectId() const { return project_; }
180
empty() const181 bool empty() const { return project_.id().empty(); }
182
operator ==(const SessionScope & other) const183 bool operator==(const SessionScope &other) const {
184 return project_ == other.project_ && id_ == other.id_;
185 }
186
operator !=(const SessionScope & other) const187 bool operator!=(const SessionScope &other) const {
188 return !(*this == other);
189 }
190
operator <(const SessionScope & other) const191 bool operator<(const SessionScope &other) const {
192 return project_ < other.project_ ||
193 (project_ == other.project_ && id_ < other.id_);
194 }
195
196 private:
197 ProjectId project_;
198 std::string id_;
199 };
200
201 SessionScopeState validateSessionScope(const SessionScope& scope,
202 const core::FilePath& userHomePath,
203 const core::FilePath& userScratchPath,
204 core::r_util::ProjectIdToFilePath projectIdToFilePath,
205 bool projectSharingEnabled,
206 std::string* pProjectFilePath);
207
208 bool isSharedPath(const std::string& projectPath,
209 const core::FilePath& userHomePath);
210
211 std::string urlPathForSessionScope(const SessionScope& scope);
212
213 std::string createSessionUrl(const std::string& hostPageUrl,
214 const SessionScope& scope);
215
216 void parseSessionUrl(const std::string& url,
217 SessionScope* pScope,
218 std::string* pUrlPrefix,
219 std::string* pUrlWithoutPrefix,
220 std::string* pBaseUrl = nullptr);
221
222
223 struct SessionContext
224 {
SessionContextrstudio::core::r_util::SessionContext225 SessionContext()
226 {
227 }
228
SessionContextrstudio::core::r_util::SessionContext229 explicit SessionContext(const std::string& username,
230 const SessionScope& scope = SessionScope())
231 : username(username), scope(scope)
232 {
233 }
234 std::string username;
235 SessionScope scope;
236
emptyrstudio::core::r_util::SessionContext237 bool empty() const { return username.empty(); }
238
operator ==rstudio::core::r_util::SessionContext239 bool operator==(const SessionContext &other) const {
240 return username == other.username && scope == other.scope;
241 }
242
operator <rstudio::core::r_util::SessionContext243 bool operator<(const SessionContext &other) const {
244 return username < other.username ||
245 (username == other.username && scope < other.scope);
246 }
247 };
248
249
250 std::ostream& operator<< (std::ostream& os, const SessionContext& context);
251
252 std::string sessionScopeFile(std::string prefix,
253 const SessionScope& scope);
254
255 std::string sessionScopePrefix(const std::string& username);
256
257 std::string sessionScopesPrefix(const std::string& username);
258
259 std::string sessionContextFile(const SessionContext& context);
260
261 std::string generateScopeId();
262 std::string generateScopeId(const std::vector<std::string>& reserved);
263
264
265 } // namespace r_util
266 } // namespace core
267 } // namespace rstudio
268
269
270 #endif // CORE_R_UTIL_R_SESSION_CONTEXT_HPP
271