Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cookie to check share link access #691

Merged
merged 7 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions fileserver/fileop.go
Original file line number Diff line number Diff line change
Expand Up @@ -527,9 +527,9 @@ func setCommonHeaders(rsp http.ResponseWriter, r *http.Request, operation, fileN
operation == "downloadblks" {
// Since the file name downloaded by safari will be garbled, we need to encode the filename.
// Safari cannot parse unencoded utf8 characters.
contFileName = fmt.Sprintf("attachment;filename*=\"utf-8' '%s\"", url.PathEscape(fileName))
contFileName = fmt.Sprintf("attachment;filename*=utf-8''%s;filename=\"%s\"", url.PathEscape(fileName), fileName)
} else {
contFileName = fmt.Sprintf("inline;filename*=\"utf-8' '%s\"", url.PathEscape(fileName))
contFileName = fmt.Sprintf("inline;filename*=utf-8''%s;filename=\"%s\"", url.PathEscape(fileName), fileName)
}
rsp.Header().Set("Content-Disposition", contFileName)

Expand Down Expand Up @@ -725,7 +725,7 @@ func downloadZipFile(rsp http.ResponseWriter, r *http.Request, data, repoID, use

// The zip name downloaded by safari will be garbled if we encode the zip name,
// because we download zip file using chunk encoding.
contFileName := fmt.Sprintf("attachment;filename=\"%s\"", zipName)
contFileName := fmt.Sprintf("attachment;filename=\"%s\";filename*=utf-8''%s", zipName, url.PathEscape(zipName))
rsp.Header().Set("Content-Disposition", contFileName)
rsp.Header().Set("Content-Type", "application/octet-stream")

Expand All @@ -744,7 +744,7 @@ func downloadZipFile(rsp http.ResponseWriter, r *http.Request, data, repoID, use
zipName := fmt.Sprintf("documents-export-%d-%d-%d.zip", now.Year(), now.Month(), now.Day())

setCommonHeaders(rsp, r, "download", zipName)
contFileName := fmt.Sprintf("attachment;filename=\"%s\"", zipName)
contFileName := fmt.Sprintf("attachment;filename=\"%s\";filename*=utf8''%s", zipName, url.PathEscape(zipName))
rsp.Header().Set("Content-Disposition", contFileName)
rsp.Header().Set("Content-Type", "application/octet-stream")

Expand Down Expand Up @@ -3499,7 +3499,7 @@ type ShareLinkInfo struct {
ShareType string `json:"share_type"`
}

func queryShareLinkInfo(token, opType string) (*ShareLinkInfo, *appError) {
func queryShareLinkInfo(token, cookie, opType string) (*ShareLinkInfo, *appError) {
claims := SeahubClaims{
time.Now().Add(time.Second * 300).Unix(),
true,
Expand All @@ -3512,10 +3512,13 @@ func queryShareLinkInfo(token, opType string) (*ShareLinkInfo, *appError) {
err := fmt.Errorf("failed to sign jwt token: %v", err)
return nil, &appError{err, "", http.StatusInternalServerError}
}
url := fmt.Sprintf("%s?token=%s&type=%s", seahubURL+"/share-link-info/", token, opType)
url := fmt.Sprintf("%s?token=%s&type=%s", seahubURL+"/check-share-link-access/", token, opType)
header := map[string][]string{
"Authorization": {"Token " + tokenString},
}
if cookie != "" {
header["Cookie"] = []string{cookie}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个请求没有设置 applicateion/json 的头部。可以在 HttpCommon 里面自动设置。HttpCommon 也需要增加请求超时。

status, body, err := utils.HttpCommon("GET", url, header, nil)
if err != nil {
err := fmt.Errorf("failed to get share link info: %v", err)
Expand Down Expand Up @@ -3548,7 +3551,8 @@ func accessLinkCB(rsp http.ResponseWriter, r *http.Request) *appError {
return &appError{nil, msg, http.StatusBadRequest}
}
token := parts[1]
info, appErr := queryShareLinkInfo(token, "file")
cookie := r.Header.Get("Cookie")
info, appErr := queryShareLinkInfo(token, cookie, "file")
if appErr != nil {
return appErr
}
Expand Down
8 changes: 5 additions & 3 deletions fileserver/utils/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import (
"io"
"net/http"
"strings"
"time"
)

var HttpReqContext, HttpReqCancel = context.WithCancel(context.Background())

func GetAuthorizationToken(h http.Header) string {
auth := h.Get("Authorization")
splitResult := strings.Split(auth, " ")
Expand All @@ -20,7 +19,10 @@ func GetAuthorizationToken(h http.Header) string {
}

func HttpCommon(method, url string, header map[string][]string, reader io.Reader) (int, []byte, error) {
req, err := http.NewRequestWithContext(HttpReqContext, method, url, reader)
header["Content-Type"] = []string{"application/json"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里设置了这个头部,就不用再调用 HttpCommon 之前设置了。多余的代码删除吧。

ctx, cancel := context.WithTimeout(context.Background(), 45*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, method, url, reader)
if err != nil {
return -1, nil, err
}
Expand Down
43 changes: 20 additions & 23 deletions server/access-file.c
Original file line number Diff line number Diff line change
Expand Up @@ -601,20 +601,17 @@ do_file(evhtp_request_t *req, SeafRepo *repo, const char *file_id,
evhtp_headers_add_header (req->headers_out,
evhtp_header_new("Content-Length", file_size, 1, 1));

char *esc_filename = g_uri_escape_string(filename, NULL, FALSE);
if (strcmp(operation, "download") == 0 ||
strcmp(operation, "download-link") == 0) {
/* Safari doesn't support 'utf8', 'utf-8' is compatible with most of browsers. */
snprintf(cont_filename, SEAF_PATH_MAX,
"attachment;filename*=\"utf-8\' \'%s\"", filename);
"attachment;filename*=utf-8''%s;filename=\"%s\"", esc_filename, filename);
} else {
if (test_firefox (req)) {
snprintf(cont_filename, SEAF_PATH_MAX,
"inline;filename*=\"utf-8\' \'%s\"", filename);
} else {
snprintf(cont_filename, SEAF_PATH_MAX,
"inline;filename=\"%s\"", filename);
}
snprintf(cont_filename, SEAF_PATH_MAX,
"inline;filename*=utf-8''%s;filename=\"%s\"", esc_filename, filename);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个需要在 Chrome, Firefox 和 Safari 三个浏览器上测试。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个测过了

}
g_free (esc_filename);
evhtp_headers_add_header(req->headers_out,
evhtp_header_new("Content-Disposition", cont_filename,
1, 1));
Expand Down Expand Up @@ -896,27 +893,20 @@ set_resp_disposition (evhtp_request_t *req, const char *operation,
const char *filename)
{
char *cont_filename = NULL;
char *esc_filename = g_uri_escape_string(filename, NULL, FALSE);

if (strcmp(operation, "download") == 0) {
if (test_firefox (req)) {
cont_filename = g_strdup_printf("attachment;filename*=\"utf-8\' \'%s\"",
filename);

} else {
cont_filename = g_strdup_printf("attachment;filename=\"%s\"", filename);
}
cont_filename = g_strdup_printf("attachment;filename*=utf-8''%s;filename=\"%s\"",
esc_filename, filename);
} else {
if (test_firefox (req)) {
cont_filename = g_strdup_printf("inline;filename*=\"utf-8\' \'%s\"",
filename);
} else {
cont_filename = g_strdup_printf("inline;filename=\"%s\"", filename);
}
cont_filename = g_strdup_printf("inline;filename*=utf-8''%s;filename=\"%s\"",
esc_filename, filename);
}

evhtp_headers_add_header(req->headers_out,
evhtp_header_new("Content-Disposition", cont_filename,
0, 1));
g_free (esc_filename);
g_free (cont_filename);
}

Expand Down Expand Up @@ -1061,8 +1051,14 @@ start_download_zip_file (evhtp_request_t *req, const char *token,
evhtp_headers_add_header (req->headers_out,
evhtp_header_new("Content-Length", file_size, 1, 1));

char *zippath = g_strdup_printf("%s.zip", zipname);
char *esc_zippath = g_uri_escape_string(zippath, NULL, FALSE);

snprintf(cont_filename, SEAF_PATH_MAX,
"attachment;filename=\"%s.zip\"", zipname);
"attachment;filename*=utf-8''%s;filename=\"%s\"", esc_zippath, zippath);

g_free (zippath);
g_free (esc_zippath);

evhtp_headers_add_header(req->headers_out,
evhtp_header_new("Content-Disposition", cont_filename, 1, 1));
Expand Down Expand Up @@ -1682,7 +1678,8 @@ access_link_cb(evhtp_request_t *req, void *arg)

token = parts[1];

info = http_tx_manager_query_share_link_info (token, "file");
const char *cookie = evhtp_kv_find (req->headers_in, "Cookie");
info = http_tx_manager_query_share_link_info (token, cookie, "file");
if (!info) {
error_str = "Link token not found\n";
error_code = EVHTP_RES_FORBIDDEN;
Expand Down
18 changes: 12 additions & 6 deletions server/http-tx-mgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ http_post (Connection *conn, const char *url, const char *token,

curl = conn->curl;

headers = curl_slist_append (headers, "User-Agent: Seafile/"SEAFILE_CLIENT_VERSION" ("USER_AGENT_OS")");
headers = curl_slist_append (headers, "User-Agent: Seafile Server/"SEAFILE_CLIENT_VERSION" ("USER_AGENT_OS")");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

后面不用加 version 了,而且你这个也是客户端的版本。这些宏也删掉吧。


if (token) {
token_header = g_strdup_printf ("Authorization: Token %s", token);
Expand Down Expand Up @@ -506,7 +506,7 @@ http_tx_manager_get_nickname (const char *modifier)
json_decref (content);

curl = conn->curl;
headers = curl_slist_append (headers, "User-Agent: Seafile/"SEAFILE_CLIENT_VERSION" ("USER_AGENT_OS")");
headers = curl_slist_append (headers, "User-Agent: Seafile Server/"SEAFILE_CLIENT_VERSION" ("USER_AGENT_OS")");
token_header = g_strdup_printf ("Authorization: Token %s", jwt_token);
headers = curl_slist_append (headers, token_header);
headers = curl_slist_append (headers, "Content-Type: application/json");
Expand Down Expand Up @@ -580,10 +580,11 @@ parse_share_link_info (const char *rsp_content, int rsp_size)
}

SeafileShareLinkInfo *
http_tx_manager_query_share_link_info (const char *token, const char *type)
http_tx_manager_query_share_link_info (const char *token, const char *cookie, const char *type)
{
Connection *conn = NULL;
char *token_header;
char *cookie_header;
struct curl_slist *headers = NULL;
int ret = 0;
CURL *curl;
Expand All @@ -607,14 +608,19 @@ http_tx_manager_query_share_link_info (const char *token, const char *type)
}

curl = conn->curl;
headers = curl_slist_append (headers, "User-Agent: Seafile/"SEAFILE_CLIENT_VERSION" ("USER_AGENT_OS")");
headers = curl_slist_append (headers, "User-Agent: Seafile Server/"SEAFILE_CLIENT_VERSION" ("USER_AGENT_OS")");
token_header = g_strdup_printf ("Authorization: Token %s", jwt_token);
headers = curl_slist_append (headers, token_header);
headers = curl_slist_append (headers, "Content-Type: application/json");
g_free (token_header);
if (cookie) {
cookie_header = g_strdup_printf ("Cookie: %s", cookie);
headers = curl_slist_append (headers, cookie_header);
g_free (cookie_header);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个代码的位置往下面移动一下吧,感觉中断了 token_header 的代码。

headers = curl_slist_append (headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

url = g_strdup_printf("%s/share-link-info/?token=%s&type=%s", seaf->seahub_url, token, type);
url = g_strdup_printf("%s/check-share-link-access/?token=%s&type=%s", seaf->seahub_url, token, type);
ret = http_get_common (curl, url, jwt_token, &rsp_status,
&rsp_content, &rsp_size, NULL, NULL, TRUE);
if (ret < 0) {
Expand Down
2 changes: 1 addition & 1 deletion server/http-tx-mgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,5 @@ char *
http_tx_manager_get_nickname (const char *modifier);

SeafileShareLinkInfo *
http_tx_manager_query_share_link_info (const char *token, const char *type);
http_tx_manager_query_share_link_info (const char *token, const char *cookie, const char *type);
#endif
9 changes: 5 additions & 4 deletions server/seaf-server.c
Original file line number Diff line number Diff line change
Expand Up @@ -1317,10 +1317,6 @@ main (int argc, char **argv)
seafile_debug_set_flags_string (debug_str);

private_key = g_getenv("JWT_PRIVATE_KEY");
if (!private_key) {
seaf_warning ("Failed to read JWT_PRIVATE_KEY.\n");
exit (1);
}

if (seafile_dir == NULL)
seafile_dir = g_build_filename (ccnet_dir, "seafile", NULL);
Expand All @@ -1344,6 +1340,11 @@ main (int argc, char **argv)
exit (0);
}

if (!private_key) {
seaf_warning ("Failed to read JWT_PRIVATE_KEY.\n");
exit (1);
}

seaf = seafile_session_new (central_config_dir, seafile_dir, ccnet_dir, private_key);
if (!seaf) {
seaf_warning ("Failed to create seafile session.\n");
Expand Down
Loading