1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3 #include "common.h"
4
5 #include <timer.h>
6
7 #include <pthread.h>
8
9 #include "seafile-session.h"
10 #include "web-accesstoken-mgr.h"
11 #include "seafile-error.h"
12
13 #include "utils.h"
14
15 #include "log.h"
16
17 #define CLEANING_INTERVAL_MSEC 1000*300 /* 5 minutes */
18 #define TOKEN_EXPIRE_TIME 3600 /* 1 hour */
19 #define TOKEN_LEN 36
20
21 struct WebATPriv {
22 GHashTable *access_token_hash; /* token -> access info */
23 pthread_mutex_t lock;
24
25 gboolean cluster_mode;
26 struct ObjCache *cache;
27 };
28 typedef struct WebATPriv WebATPriv;
29
30 /* #define DEBUG 1 */
31
32 typedef struct {
33 char *repo_id;
34 char *obj_id;
35 char *op;
36 char *username;
37 long expire_time;
38 gboolean use_onetime;
39 } AccessInfo;
40
41 static void
free_access_info(AccessInfo * info)42 free_access_info (AccessInfo *info)
43 {
44 if (!info)
45 return;
46
47 g_free (info->repo_id);
48 g_free (info->obj_id);
49 g_free (info->op);
50 g_free (info->username);
51 g_free (info);
52 }
53
54 SeafWebAccessTokenManager*
seaf_web_at_manager_new(SeafileSession * session)55 seaf_web_at_manager_new (SeafileSession *session)
56 {
57 SeafWebAccessTokenManager *mgr = g_new0 (SeafWebAccessTokenManager, 1);
58
59 mgr->seaf = session;
60
61 mgr->priv = g_new0(WebATPriv, 1);
62 mgr->priv->access_token_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
63 g_free,
64 (GDestroyNotify)free_access_info);
65 pthread_mutex_init (&mgr->priv->lock, NULL);
66
67 return mgr;
68 }
69
70 static gboolean
remove_expire_info(gpointer key,gpointer value,gpointer user_data)71 remove_expire_info (gpointer key, gpointer value, gpointer user_data)
72 {
73 AccessInfo *info = (AccessInfo *)value;
74 long now = *((long*)user_data);
75
76 if (info && now >= info->expire_time) {
77 return TRUE;
78 }
79
80 return FALSE;
81 }
82
83 static int
clean_pulse(void * vmanager)84 clean_pulse (void *vmanager)
85 {
86 SeafWebAccessTokenManager *manager = vmanager;
87 long now = (long)time(NULL);
88
89 pthread_mutex_lock (&manager->priv->lock);
90
91 g_hash_table_foreach_remove (manager->priv->access_token_hash,
92 remove_expire_info, &now);
93
94 pthread_mutex_unlock (&manager->priv->lock);
95
96 return TRUE;
97 }
98
99 int
seaf_web_at_manager_start(SeafWebAccessTokenManager * mgr)100 seaf_web_at_manager_start (SeafWebAccessTokenManager *mgr)
101 {
102 ccnet_timer_new (clean_pulse, mgr, CLEANING_INTERVAL_MSEC);
103
104 return 0;
105 }
106
107 static char *
gen_new_token(GHashTable * token_hash)108 gen_new_token (GHashTable *token_hash)
109 {
110 char uuid[37];
111 char *token;
112
113 while (1) {
114 gen_uuid_inplace (uuid);
115 token = g_strndup(uuid, TOKEN_LEN);
116
117 /* Make sure the new token doesn't conflict with an existing one. */
118 if (g_hash_table_lookup (token_hash, token) != NULL)
119 g_free (token);
120 else
121 return token;
122 }
123 }
124
125 char *
seaf_web_at_manager_get_access_token(SeafWebAccessTokenManager * mgr,const char * repo_id,const char * obj_id,const char * op,const char * username,int use_onetime,GError ** error)126 seaf_web_at_manager_get_access_token (SeafWebAccessTokenManager *mgr,
127 const char *repo_id,
128 const char *obj_id,
129 const char *op,
130 const char *username,
131 int use_onetime,
132 GError **error)
133 {
134 AccessInfo *info;
135 long now = (long)time(NULL);
136 long expire;
137 char *t;
138 SeafileWebAccess *webaccess;
139
140 if (strcmp(op, "view") != 0 &&
141 strcmp(op, "download") != 0 &&
142 strcmp(op, "downloadblks") != 0 &&
143 strcmp(op, "download-dir") != 0 &&
144 strcmp(op, "download-multi") != 0 &&
145 strcmp(op, "download-link") != 0 &&
146 strcmp(op, "download-dir-link") != 0 &&
147 strcmp(op, "download-multi-link") != 0 &&
148 strcmp(op, "upload") != 0 &&
149 strcmp(op, "update") != 0 &&
150 strcmp(op, "upload-link") != 0 &&
151 strcmp(op, "upload-blks-api") != 0 &&
152 strcmp(op, "upload-blks-aj") != 0 &&
153 strcmp(op, "update-blks-api") != 0 &&
154 strcmp(op, "update-blks-aj") != 0) {
155 g_set_error (error, SEAFILE_DOMAIN, SEAF_ERR_GENERAL,
156 "Invalid operation type.");
157 return NULL;
158 }
159
160 pthread_mutex_lock (&mgr->priv->lock);
161
162 t = gen_new_token (mgr->priv->access_token_hash);
163 expire = now + seaf->http_server->web_token_expire_time;
164
165 info = g_new0 (AccessInfo, 1);
166 info->repo_id = g_strdup (repo_id);
167 info->obj_id = g_strdup (obj_id);
168 info->op = g_strdup (op);
169 info->username = g_strdup (username);
170 info->expire_time = expire;
171 if (use_onetime) {
172 info->use_onetime = TRUE;
173 }
174
175 g_hash_table_insert (mgr->priv->access_token_hash, g_strdup(t), info);
176
177 pthread_mutex_unlock (&mgr->priv->lock);
178
179 if (strcmp(op, "download-dir") == 0 ||
180 strcmp(op, "download-multi") == 0 ||
181 strcmp(op, "download-dir-link") == 0 ||
182 strcmp(op, "download-multi-link") == 0) {
183
184 webaccess = g_object_new (SEAFILE_TYPE_WEB_ACCESS,
185 "repo_id", info->repo_id,
186 "obj_id", info->obj_id,
187 "op", info->op,
188 "username", info->username,
189 NULL);
190
191 if (zip_download_mgr_start_zip_task (seaf->zip_download_mgr,
192 t, webaccess, error) < 0) {
193 pthread_mutex_lock (&mgr->priv->lock);
194 g_hash_table_remove (mgr->priv->access_token_hash, t);
195 pthread_mutex_unlock (&mgr->priv->lock);
196
197 g_object_unref (webaccess);
198 g_free (t);
199 return NULL;
200 }
201 g_object_unref (webaccess);
202 }
203
204 return t;
205 }
206
207 SeafileWebAccess *
seaf_web_at_manager_query_access_token(SeafWebAccessTokenManager * mgr,const char * token)208 seaf_web_at_manager_query_access_token (SeafWebAccessTokenManager *mgr,
209 const char *token)
210 {
211 SeafileWebAccess *webaccess;
212 AccessInfo *info;
213
214 pthread_mutex_lock (&mgr->priv->lock);
215 info = g_hash_table_lookup (mgr->priv->access_token_hash, token);
216 pthread_mutex_unlock (&mgr->priv->lock);
217
218 if (info != NULL) {
219 long expire_time = info->expire_time;
220 long now = (long)time(NULL);
221
222 if (now - expire_time >= 0) {
223 return NULL;
224 } else {
225 webaccess = g_object_new (SEAFILE_TYPE_WEB_ACCESS,
226 "repo_id", info->repo_id,
227 "obj_id", info->obj_id,
228 "op", info->op,
229 "username", info->username,
230 NULL);
231
232 if (info->use_onetime) {
233 pthread_mutex_lock (&mgr->priv->lock);
234 g_hash_table_remove (mgr->priv->access_token_hash, token);
235 pthread_mutex_unlock (&mgr->priv->lock);
236 }
237
238 return webaccess;
239 }
240 }
241
242 return NULL;
243 }
244