-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathkuaipan-uploader-dev-share.html
654 lines (539 loc) · 41.9 KB
/
kuaipan-uploader-dev-share.html
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
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><title>kuaipan_uploader开发分享 | 王恒's Blog</title><meta name="keywords" content="Windows,Linux,备份,awk,curl,shell,开源"><meta name="author" content="王恒"><meta name="copyright" content="王恒"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="PS:将原来的一篇文章拆开了,上篇是安装使用讲解,这篇是开发过程讲解。 以前使用dropbox的linux客户端备份VPS上的文件和数据,但是近来dorpbox在国内越来越难访问,加上dropbox本身的容量只有几G,于是有了自己动刀写一个网盘的客户端,首先想到的是百度网盘,2T的巨大容量肯定是够用了! 没想到这个决定却是悲剧的开始,按照百度PCS的API文档写了半天,没想到PCS开通居然审核">
<meta property="og:type" content="article">
<meta property="og:title" content="kuaipan_uploader开发分享">
<meta property="og:url" content="http://wangheng.org/kuaipan-uploader-dev-share.html">
<meta property="og:site_name" content="王恒's Blog">
<meta property="og:description" content="PS:将原来的一篇文章拆开了,上篇是安装使用讲解,这篇是开发过程讲解。 以前使用dropbox的linux客户端备份VPS上的文件和数据,但是近来dorpbox在国内越来越难访问,加上dropbox本身的容量只有几G,于是有了自己动刀写一个网盘的客户端,首先想到的是百度网盘,2T的巨大容量肯定是够用了! 没想到这个决定却是悲剧的开始,按照百度PCS的API文档写了半天,没想到PCS开通居然审核">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg">
<meta property="article:published_time" content="2015-05-27T05:01:02.000Z">
<meta property="article:modified_time" content="2021-11-20T16:23:38.550Z">
<meta property="article:author" content="王恒">
<meta property="article:tag" content="Windows">
<meta property="article:tag" content="Linux">
<meta property="article:tag" content="备份">
<meta property="article:tag" content="awk">
<meta property="article:tag" content="curl">
<meta property="article:tag" content="shell">
<meta property="article:tag" content="开源">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg"><link rel="shortcut icon" href="/img/favicon.ico"><link rel="canonical" href="http://wangheng.org/kuaipan-uploader-dev-share"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.min.css" media="print" onload="this.media='all'"><script async defer data-website-id="ddf4c251-6dc0-46f0-8b55-f3b5b1b5b13c" src="https://ds.apiof.com:13002/umami.js"></script><script>const GLOBAL_CONFIG = {
root: '/',
algolia: undefined,
localSearch: {"path":"/search.xml","preload":false,"languages":{"hits_empty":"找不到您查询的内容:${query}"}},
translate: undefined,
noticeOutdate: undefined,
highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
copy: {
success: '复制成功',
error: '复制错误',
noSupport: '浏览器不支持'
},
relativeDate: {
homepage: false,
post: false
},
runtime: '',
date_suffix: {
just: '刚刚',
min: '分钟前',
hour: '小时前',
day: '天前',
month: '个月前'
},
copyright: {"limitCount":50,"languages":{"author":"作者: 王恒","link":"链接: ","source":"来源: 王恒's Blog","info":"著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。"}},
lightbox: 'fancybox',
Snackbar: undefined,
source: {
justifiedGallery: {
js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
}
},
isPhotoFigcaption: false,
islazyload: true,
isAnchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
title: 'kuaipan_uploader开发分享',
isPost: true,
isHome: false,
isHighlightShrink: false,
isToc: false,
postUpdate: '2021-11-21 00:23:38'
}</script><noscript><style type="text/css">
#nav {
opacity: 1
}
.justified-gallery img {
opacity: 1
}
#recent-posts time,
#post-meta time {
display: inline !important
}
</style></noscript><script>(win=>{
win.saveToLocal = {
set: function setWithExpiry(key, value, ttl) {
if (ttl === 0) return
const now = new Date()
const expiryDay = ttl * 86400000
const item = {
value: value,
expiry: now.getTime() + expiryDay,
}
localStorage.setItem(key, JSON.stringify(item))
},
get: function getWithExpiry(key) {
const itemStr = localStorage.getItem(key)
if (!itemStr) {
return undefined
}
const item = JSON.parse(itemStr)
const now = new Date()
if (now.getTime() > item.expiry) {
localStorage.removeItem(key)
return undefined
}
return item.value
}
}
win.getScript = url => new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = url
script.async = true
script.onerror = reject
script.onload = script.onreadystatechange = function() {
const loadState = this.readyState
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
script.onload = script.onreadystatechange = null
resolve()
}
document.head.appendChild(script)
})
win.activateDarkMode = function () {
document.documentElement.setAttribute('data-theme', 'dark')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
}
}
win.activateLightMode = function () {
document.documentElement.setAttribute('data-theme', 'light')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
}
}
const t = saveToLocal.get('theme')
if (t === 'dark') activateDarkMode()
else if (t === 'light') activateLightMode()
const asideStatus = saveToLocal.get('aside-status')
if (asideStatus !== undefined) {
if (asideStatus === 'hide') {
document.documentElement.classList.add('hide-aside')
} else {
document.documentElement.classList.remove('hide-aside')
}
}
const detectApple = () => {
if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
document.documentElement.classList.add('apple')
}
}
detectApple()
})(window)</script><meta name="generator" content="Hexo 5.4.2"></head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src= "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-lazy-src="/img/avatar.png" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">86</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">132</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">7</div></a></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间线</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/wiki/"><i class="fa-fw fas fa-pencil-alt"></i><span> 笔记</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友情链接</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 其他</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/projects/"><i class="fa-fw fas fa-boxes"></i><span> 作品</span></a></li><li><a class="site-page child" href="/files/"><i class="fa-fw fas fa-folder-open"></i><span> 文件</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="not-top-img" id="page-header"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">王恒's Blog</a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间线</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/wiki/"><i class="fa-fw fas fa-pencil-alt"></i><span> 笔记</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友情链接</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 其他</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/projects/"><i class="fa-fw fas fa-boxes"></i><span> 作品</span></a></li><li><a class="site-page child" href="/files/"><i class="fa-fw fas fa-folder-open"></i><span> 文件</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav></header><main class="layout" id="content-inner"><div id="post"><div id="post-info"><h1 class="post-title">kuaipan_uploader开发分享</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2015-05-27T05:01:02.000Z" title="发表于 2015-05-27 13:01:02">2015-05-27</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2021-11-20T16:23:38.550Z" title="更新于 2021-11-21 00:23:38">2021-11-21</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/linux/">linux</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="kuaipan_uploader开发分享"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div><article class="post-content" id="article-container"><content>
<strong><em>PS:将原来的一篇文章拆开了,<a href="http://wangheng.org/kuaipan-uploader.html">上篇</a>是安装使用讲解,这篇是开发过程讲解。</em></strong>
<p>以前使用dropbox的linux客户端<a href="http://wangheng.org/site-backup-to-ftp-and-dropbox.html">备份</a>VPS上的文件和数据,但是近来dorpbox在国内越来越难访问,加上dropbox本身的容量只有几G,于是有了自己动刀写一个网盘的客户端,首先想到的是百度网盘,2T的巨大容量肯定是够用了!</p>
<p>没想到这个决定却是悲剧的开始,按照百度PCS的API文档写了半天,没想到PCS开通居然审核了一周多还不通过! 联系客服,没想到他们的PCS API已经不审核新的申请了!再次吐槽下,你不审核,申请的时候就不能给个提示么!!! 遂放弃!</p>
<p>然后就想到了还是用金山快盘吧,前段时间刚被迅雷收购,速度方面应该是没有问题。找到金山快盘的官方开放平台,看了看文档似乎是…有点麻烦啊。不过本着有难度才有挑战的原则,还是开搞了。下面介绍下开发过程中遇到的一些问题。</p>
<p>首先就是快盘的授权机制,本来是不太复杂,但是它的授权流程签名并不支持PLAINTEXT明文文本格式,只支持了一个HMAC-SHA1加密方式。为了处理这个签名倒是走了一些弯路。</p>
<p>拿到授权token的过程可以总结为三歩走:</p>
<blockquote><ol>
<li>获取未授权的临时 token;</li>
<li>用户登陆并授权你的应用;</li>
<li>根据临时 token换取真实的 access_token。</li></ol></blockquote>
<p>图示如下:</p>
<p><a href="uploads/2015/05/oauth_info.png"><img class="alignleft wp-image-95093" src= "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-lazy-src="uploads/2015/05/oauth_info-300x179.png" alt="授权流程" width="330" height="197" /></a></p>
<p>在每次请求中,下面几个参数是必须的</p>
<table width="600"><tbody><tr><td><strong>Name</strong></td><td><strong>Required</strong></td><td width="77"><strong>Type </strong><strong>and Limit</strong></td><td width="387"><strong>Description</strong></td></tr><tr><td>oauth_consumer_key</td><td>Y</td><td width="77">string</td><td width="387">第1步的 consumer_key</td></tr><tr><td>oauth_signature</td><td>Y</td><td width="77">string</td><td width="387">本次请求的签名,生成方法请参考<a target="_blank" rel="noopener" href="http://www.kuaipan.cn/developers/document_signature.htm">附录-签名生成算法</a></td></tr><tr><td>oauth_timestamp</td><td>Y</td><td width="77">int</td><td width="387">时间戳,正整数,和标准时间不超过5分钟</td></tr><tr><td>oauth_nonce</td><td>Y</td><td width="77">string</td><td width="387">[ 0-9A-Za-z_ ]随机字符串,长度小于32字节。每次请求请使用不同的nonce</td></tr></tbody></table>
oauth_consumer_key可以在你创建应用的时候拿到,oauth_timestamp为标准的unix时间戳格式,oauth_nonce每次都生成一个随机数,这几个参数都非常好处理,主要就是oauth_signature这个费些周章。
<p>官方的OAuth签名生成讲的比较具体,其实获取签名的方式也非常简单:</p>
<ul>
<li>计算串基</li>
<li>根据串基按HMAC-SHA1获取签名并使用bash64和url_encode 转码</li></ul>
生成签名的时候,如果是申请request_token 那么HMAC_SHA1加密的key 就是你的consumer_secret+&,其他都是consumer_secret+&+oauth_token_secret!
<p>Linux shell中处理url_encode 没有太好的办法,我索性就写了一个函数用sed处理了,代码如下:</p>
<pre class="brush: bash; gutter: true">#url encode
function url_encode
{
url=$1
echo -n $(echo -n "$url" | sed 's/\%/\%25/g'|sed 's/&/\%26/g' |sed 's/:/\%3A/g' |sed 's/\//\%2F/g'| sed 's/=/\%3D/g' |sed 's/ /\%20/g' |sed 's/@/\%40/g' |sed 's/+/\%2B/g' |sed 's/\*/\%2A/g')
}</pre>
<p>拼接字符串基可归结为:请求方式&url_encode(请求URL)&(url_encode(参数1+参数2… ))</p>
<p>使用bash获取签名处理方法如下:</p>
<pre class="brush: bash; gutter: true">function get_signature
{
method=$1
url=$2
data=$3
token_secret=$4
baseUrl="$1&$(url_encode "$2")&$(url_encode "$3")"
signature=$(echo -n $baseUrl | openssl dgst -sha1 -binary -hmac "$APP_CONSUMER_SECRET&$token_secret" |base64)
echo -n $(url_encode $signature)
}</pre><span id="more"></span>
<p>有了签名,一切都简单了。按照官方开发文档上参数列表把其他必选的参数拼好就行了。</p>
<p>请求使用的curl,命令格式如下:</p>
<p>Curl –s –S –L –d “参数” “请求的URL” –o “本地缓存文件”</p>
<p>整个脚本的源码如下:</p>
<pre class="brush: bash; gutter: true">#!/usr/bin/env bash
#
# KuaiPan Uploader
#
#===========================================================================
# Copyright (C) 2014-2015 wangheng <[email protected]>
#
# This file is part of Kuaipan Uploader source code.
#
# Kuaipan Uploader is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the License,
# or (at your option) any later version.
#
# Kuaipan Uploader 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Foobar; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#===========================================================================
#===========================================================================
# FileName: kuaipan_uploader.sh
# Desc: API Doc is: http://www.kuaipan.cn/developers/document.htm
# Author: wangheng
# Email: [email protected]
# HomePage: http://wangheng.org
# Version: 1.0.1
# LastChange: 2015-05-09 09:34:59
# History:
#===========================================================================
#配置文件.
CONFIG_FILE=~/.kuaipan_upload.conf
RESPONSE_FILE="/tmp/resp_kuaipan"
COOKIE_FILE="/tmp/kuaipan.cookie"
Version="1.0.1"
#使用整个快盘此处填"kuaipan",使用应用目录填"app_folder"
ROOT_DIR="app_folder"
#这里改为你自己应用的consumer_key和consumer_secret_key
APP_CONSUMER_KEY="xc0kwh2EAKlTQqCd"
APP_CONSUMER_SECRET="6mnnfufVvWzPzOgb"
#授权相关
API_REQUEST_TOKEN_URL="https://openapi.kuaipan.cn/open/requestToken"
API_USER_AUTH_URL="https://www.kuaipan.cn/api.php?ac=open&op=authorise&oauth_token="
API_AUTH_TOKEN_URL="https://openapi.kuaipan.cn/open/accessToken"
#统计信息相关
API_ACCOUNT_INFO_URL="http://openapi.kuaipan.cn/1/account_info"
API_METADATA_URL="http://openapi.kuaipan.cn/1/metadata"
#上传、下载、删除
API_UPLOAD_REQUEST_URL="http://api-content.dfs.kuaipan.cn/1/fileops/upload_locate"
API_DOWNLOAD_URL="http://api-content.dfs.kuaipan.cn/1/fileops/download_file"
API_DELETE_FILE_URL="http://openapi.kuaipan.cn/1/fileops/delete"
Dependents="curl sed awk basename date grep tr od openssl base64"
CURL="curl"
#检查程序的依赖项
for i in $Dependents; do
which $i > /dev/null
if [ $? -ne 0 ]; then
echo -e "Error: $i Not Found"
exit 1
fi
done
#清理环境
if [ -f "$RESPONSE_FILE" ]; then
rm -f $RESPONSE_FILE
fi
#==========通用方法========
function get_json_value()
{
KEY=$1
echo $(cat $RESPONSE_FILE| sed 's/ //g'| sed -n 's/.*'$KEY'":"\([a-zA-Z0-9\.\-\/:]*\)".*/\1/p')
}
#get unix timestamp
function unix_time
{
echo $(date +%s)
}
#url encode
function url_encode
{
url=$1
echo -n $(echo -n "$url" | sed 's/\%/\%25/g'|sed 's/&/\%26/g' |sed 's/:/\%3A/g' |sed 's/\//\%2F/g'| sed 's/=/\%3D/g' |sed 's/ /\%20/g' |sed 's/@/\%40/g' |sed 's/+/\%2B/g' |sed 's/\*/\%2A/g')
#echo -ne $(echo $url |tr -d '\n' |od -An -tx1 |tr '[a-z]' '[A-Z]' |tr ' ' \%)
}
#url decode
function url_decode
{
url=$1
echo -ne $(echo -n $url | sed 's/\\/\\\\/g;s/\(%\)\([0-9a-fA-F][0-9a-fA-F]\)/\\x\2/g')"\n"
}
function get_signature
{
method=$1
url=$2
data=$3
token_secret=$4
baseUrl="$1&$(url_encode "$2")&$(url_encode "$3")"
signature=$(echo -n $baseUrl | openssl dgst -sha1 -binary -hmac "$APP_CONSUMER_SECRET&$token_secret" |base64)
echo -n $(url_encode $signature)
}
function account_setup
{
#1. 获取未授权的临时 token;
DATA="oauth_consumer_key=$APP_CONSUMER_KEY&oauth_nonce=$RANDOM&oauth_signature_method=HMAC-SHA1&oauth_timestamp=$(unix_time)&oauth_version=1.0"
oauth_signature=$(get_signature 'GET' $API_REQUEST_TOKEN_URL "$DATA")
$CURL -k -s -S --globoff -L -G -d "$DATA&oauth_signature=$oauth_signature" "$API_REQUEST_TOKEN_URL" -o "$RESPONSE_FILE"
tmp_oauth_token=$(get_json_value 'oauth_token')
tmp_oauth_token_secret=$(get_json_value 'oauth_token_secret')
#2. 浏览器访问URL获取授权
echo -ne "\nVisit this URL from your Browser, and login with your kuaipan account\n"
echo -ne "\n --> $API_USER_AUTH_URL$tmp_oauth_token \n"
echo -ne "\nPress enter when done...\n"
read
#3. 获取真实oauth_token
DATA="oauth_consumer_key=$APP_CONSUMER_KEY&oauth_nonce=$RANDOM&oauth_signature_method=HMAC-SHA1&oauth_timestamp=$(unix_time)&oauth_token=$tmp_oauth_token"
oauth_signature=$(get_signature 'GET' $API_AUTH_TOKEN_URL "$DATA" $tmp_oauth_token_secret)
$CURL -k -s -S -L -G -d "$DATA&oauth_signature=$oauth_signature" $API_AUTH_TOKEN_URL -o "$RESPONSE_FILE"
OAUTH_TOKEN=$(get_json_value 'oauth_token')
OAUTH_TOKEN_SECRET=$(get_json_value 'oauth_token_secret')
if [ -n "$OAUTH_TOKEN" -a -n "$OAUTH_TOKEN_SECRET" -a -n "$APP_CONSUMER_KEY" ]; then
echo -ne "Congratulations!!! login succeed!\n"
#Saving data
echo "APP_CONSUMER_KEY:$APP_CONSUMER_KEY" > "$CONFIG_FILE"
echo "APP_CONSUMER_SECRET:$APP_CONSUMER_SECRET" >> "$CONFIG_FILE"
echo "OAUTH_TOKEN:$OAUTH_TOKEN" >> "$CONFIG_FILE"
echo "OAUTH_TOKEN_SECRET:$OAUTH_TOKEN_SECRET" >> "$CONFIG_FILE"
echo -ne "All saved as $CONFIG_FILE!\n\n"
else
echo -ne "Unfortunately!!! login failed! please retray or contact [email protected] for help! \n\n"
fi
}
function account_relink
{
echo -ne "Warrning: \nAre you sure? [y/n]y"
read aw
if [ "$aw" == "n" ];then
echo -ne "Cancelled! \n"
else
rm -f "$CONFIG_FILE"
account_setup
fi
}
#========== First Setup ==========
#先检查本地是否存在配置文件
if [ -f "$CONFIG_FILE" ]; then
APP_CONSUMER_KEY=$(sed -n 's/APP_CONSUMER_KEY:\([a-zA-Z0-9]*\)/\1/p' "$CONFIG_FILE")
APP_CONSUMER_SECRET=$(sed -n 's/APP_CONSUMER_SECRET:\([a-zA-Z0-9]*\)/\1/p' "$CONFIG_FILE")
OAUTH_TOKEN=$(sed -n 's/OAUTH_TOKEN:\([a-zA-Z0-9\.]*\)/\1/p' "$CONFIG_FILE")
OAUTH_TOKEN_SECRET=$(sed -n 's/OAUTH_TOKEN_SECRET:\([a-zA-Z0-9\.]*\)/\1/p' "$CONFIG_FILE")
if [ -z "$APP_CONSUMER_KEY" -o -z "$APP_CONSUMER_SECRET" -o -z "$OAUTH_TOKEN" -o -z "$OAUTH_TOKEN_SECRET" ]; then
echo -ne "Cannot loading data from $CONFIG_FILE...\n"
echo -ne "Please run [$0 relink] to retray! \n"
exit 1
fi
#新用户,获取Token并保存到配置文件
else
account_setup
fi
#========= OAUTH API 功能实现 =========
function get_common_oauthdata
{
echo "oauth_consumer_key=$APP_CONSUMER_KEY&oauth_nonce=$RANDOM&oauth_signature_method=HMAC-SHA1&oauth_timestamp=$(unix_time)&oauth_token=$OAUTH_TOKEN"
}
#获取用户信息
function account_info()
{
OAUTH_DATA="oauth_consumer_key=$APP_CONSUMER_KEY&oauth_nonce=$RANDOM&oauth_signature_method=HMAC-SHA1&oauth_timestamp=$(unix_time)&oauth_token=$OAUTH_TOKEN"
signature=$(get_signature 'GET' $API_ACCOUNT_INFO_URL "$OAUTH_DATA" $OAUTH_TOKEN_SECRET)
$CURL -k -s -S -G -L -d "$OAUTH_DATA&oauth_signature=$signature" "$API_ACCOUNT_INFO_URL" -o "$RESPONSE_FILE"
userName=$(sed -n 's/.*user_name":"\([a-zA-Z0-9\.\-\@]*\)".*/\1/p' $RESPONSE_FILE)
let quota_total=$(sed -n 's/.*quota_total":\([0-9]*\),.*/\1/p' $RESPONSE_FILE)/1024/1024/1024
let quota_used=$(sed -n 's/.*quota_used":\([0-9]*\),.*/\1/p' $RESPONSE_FILE)/1024/1024/1024
echo ""
echo "User Name: $userName"
echo "Total Quota: $quota_total GB"
echo "Used Quota: $quota_used GB"
echo ""
}
#文件上传
function file_upload
{
local overwrite=$1
local file_Local=$2
local file_Remote=$3
if [ -z "$file_Remote" ]; then
file_Remote=$(basename "$file_Local")
fi
OAUTH_DATA=$(get_common_oauthdata)
signature=$(get_signature 'GET' $API_UPLOAD_REQUEST_URL "$OAUTH_DATA" $OAUTH_TOKEN_SECRET)
$CURL -k -s -S -G -L -d "$OAUTH_DATA&oauth_signature=$signature" "$API_UPLOAD_REQUEST_URL" -o "$RESPONSE_FILE"
upload_url=$(get_json_value "url")"1/fileops/upload_file"
#echo $upload_url
OAUTH_DATA="oauth_consumer_key=$APP_CONSUMER_KEY&oauth_nonce=$RANDOM&oauth_signature_method=HMAC-SHA1&oauth_timestamp=$(unix_time)&oauth_token=$OAUTH_TOKEN&overwrite=$overwrite&path=$(url_encode $file_Remote)&root=app_folder"
signature=$(get_signature 'POST' $upload_url "$OAUTH_DATA" $OAUTH_TOKEN_SECRET)
$CURL -k --progress-bar -i -o "$RESPONSE_FILE" -F "file=@$file_Local" "$upload_url?$OAUTH_DATA&oauth_signature=$signature"
grep "HTTP/1.1 200 OK" "$RESPONSE_FILE" > /dev/null
if [ $? -eq 0 ]; then
echo -ne "--Upload Success.\n"
else
echo -ne "--Upload Failed.\n"
echo -ne "--Error occurred while uploading $file_Local.\n"
exit 1
fi
#cat $RESPONSE_FILE
}
#下载文件
function file_download
{
local file_Remote=$1
local file_Local=$2
echo -ne "Begin to download $file_Remote...\n"
OAUTH_DATA=$(get_common_oauthdata)"&path=$(url_encode $file_Remote)&root=$ROOT_DIR"
signature=$(get_signature 'GET' $API_DOWNLOAD_URL "$OAUTH_DATA" $OAUTH_TOKEN_SECRET)
#$CURL -S -L -v -G -d "$OAUTH_DATA&oauth_signature=$signature" "$API_DOWNLOAD_URL" -o "$file_Local"
$CURL -L --compressed --progress-bar -G -D "$RESPONSE_FILE" -d "$OAUTH_DATA&oauth_signature=$signature" "$API_DOWNLOAD_URL" --cookie-jar "$COOKIE_FILE" -o "$file_Local"
rm -f $COOKIE_FILE
grep "HTTP/1.1 200 OK" "$RESPONSE_FILE" > /dev/null
if [ $? -eq 0 ]; then
echo -ne "--Download Success.\n"
else
echo -ne "--Download Failed.\n"
exit 1
fi
}
#删除文件
function file_delete
{
local file_Remote=$1
OAUTH_DATA=$(get_common_oauthdata)"&path=$file_Remote&root=$ROOT_DIR"
signature=$(get_signature 'GET' $API_DELETE_FILE_URL "$OAUTH_DATA" $OAUTH_TOKEN_SECRET)
$CURL -k -s -S -i -S -L -G -d "$OAUTH_DATA&oauth_signature=$signature" "$API_DELETE_FILE_URL" -o "$RESPONSE_FILE"
grep "HTTP/1.1 200 OK" "$RESPONSE_FILE" > /dev/null
if [ $? -eq 0 ]; then
echo -ne "\033[0;32;1m--Delete Success.\033[0m\n"
else
echo -ne "\033[0;31;1m--Delete Failed.\033[0m\n"
exit 1
fi
echo ""
}
#显示文件夹信息,默认显示根目录
function show_list
{
local remote_path=$1
local metaUrl="$API_METADATA_URL/$ROOT_DIR/$remote_path"
OAUTH_DATA=$(get_common_oauthdata)
signature=$(get_signature 'GET' $metaUrl "$OAUTH_DATA" $OAUTH_TOKEN_SECRET)
$CURL -k -s -S -G -L -d "$OAUTH_DATA&oauth_signature=$signature" "$metaUrl" -o "$RESPONSE_FILE"
sed 's/,/\n/g' $RESPONSE_FILE|grep name|awk -F ':' '{print $2}'|tr -d '"'|tr "\n" "\t"|sed 's/$/\n/'
}
#=====================================
function usage() {
echo -e "KuaiPan Uploader v$Version"
echo -e "wangheng - [email protected]\n"
echo -e "Usage: $0 COMMAND [PARAMETERS]..."
echo -e "\nCommands:"
echo -e "\t upload [local file] <remote file>"
echo -e "\t download [remote file] <local file>"
echo -e "\t delete [remote file/remote dir]"
echo -e "\t list <remote dir>"
echo -e "\t info"
echo -e "\t relink"
echo -en "\nFor more informations, please visit \033[0;32;1m http://wangheng.org.\033[0m \n\n"
exit 1
}
#===============Main =================
COMMAND=$1
case $COMMAND in
upload)
file_Local=$2
file_Remote=$3
#检查本地文件是否存在
if [ ! -f "$file_Local" ]; then
echo -e "Error: Please specify a valid source file!"
exit 1
fi
file_upload "True" "$file_Local" "$file_Remote"
;;
download)
file_Remote=$2
file_Local=$3
if [ -z "$file_Remote" ]; then
echo -ne "Error: Please input a valid remote file.\n"
exit 1
fi
if [ -z "$file_Local" ]; then
file_Local=$(basename "$file_Remote")
fi
file_download "$file_Remote" "$file_Local"
;;
info)
account_info
;;
delete)
file_Remote=$2
if [ -z "$file_Remote" ]; then
echo -ne "Error: Please input a valid remote file.\n"
exit 1
fi
file_delete "$file_Remote"
;;
list)
RemoteDir=$2
if [ -z "$RemoteDir" ]; then
RemoteDir="/"
fi
show_list "$RemoteDir"
;;
relink)
account_relink
;;
*)
usage
;;
esac</pre>
<p> </p>
<p><strong>项目开源在我的Github</strong>:<a target="_blank" rel="noopener" href="https://github.com/wujiwh/kuaipan_uploader">https://github.com/wujiwh/kuaipan_uploader</a></p>
<p>欢迎大家多多交流~~<br></content></p>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="http://wangheng.org">王恒</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="http://wangheng.org/kuaipan-uploader-dev-share.html">http://wangheng.org/kuaipan-uploader-dev-share.html</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="http://wangheng.org" target="_blank">王恒's Blog</a>!</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/Windows/">Windows</a><a class="post-meta__tags" href="/tags/Linux/">Linux</a><a class="post-meta__tags" href="/tags/%E5%A4%87%E4%BB%BD/">备份</a><a class="post-meta__tags" href="/tags/awk/">awk</a><a class="post-meta__tags" href="/tags/curl/">curl</a><a class="post-meta__tags" href="/tags/shell/">shell</a><a class="post-meta__tags" href="/tags/%E5%BC%80%E6%BA%90/">开源</a></div><div class="post_share"><div class="social-share" data-image="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" data-sites="wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/migrating-from-wordpress-to-hexo.html"><img class="prev-cover" src= "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-lazy-src="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">从wordpress迁移到hexo填坑</div></div></a></div><div class="next-post pull-right"><a href="/kuaipan-uploader.html"><img class="next-cover" src= "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-lazy-src="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">linux版快盘上传下载脚本</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><div><a href="/kuaipan-uploader.html" title="linux版快盘上传下载脚本"><img class="cover" src= "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-lazy-src="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2015-05-13</div><div class="title">linux版快盘上传下载脚本</div></div></a></div><div><a href="/cmd-in-window-property-the-settings.html" title="CMD窗口属性设置"><img class="cover" src= "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-lazy-src="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2012-05-20</div><div class="title">CMD窗口属性设置</div></div></a></div><div><a href="/efficient-office-support-tool-autohotkey.html" title="高效办公辅助工具Autohotkey"><img class="cover" src= "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-lazy-src="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2012-06-09</div><div class="title">高效办公辅助工具Autohotkey</div></div></a></div><div><a href="/iis-identify-attributes-targetframework-managedpipelinehandler.html" title="IIS无法识别的属性targetFramework、错误模块ManagedPipelineHandler"><img class="cover" src= "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-lazy-src="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2012-04-25</div><div class="title">IIS无法识别的属性targetFramework、错误模块ManagedPipelineHandler</div></div></a></div><div><a href="/implementation-windows-version-the-the-the-cron.html" title="C#实现Windows版Cron"><img class="cover" src= "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-lazy-src="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2012-06-10</div><div class="title">C#实现Windows版Cron</div></div></a></div><div><a href="/manually-produced-vpn-login.html" title="手动制作VPN登录器"><img class="cover" src= "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-lazy-src="https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2012-06-12</div><div class="title">手动制作VPN登录器</div></div></a></div></div></div><hr/><div id="post-comment"><div class="comment-head"><div class="comment-headline"><i class="fas fa-comments fa-fw"></i><span> 评论</span></div></div><div class="comment-wrap"><div><div id="disqus_thread"></div></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src= "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-lazy-src="/img/avatar.png" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">王恒</div><div class="author-info__description">make progress little day by day.</div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">86</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">132</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">7</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/all4fun"><i class="fab fa-github"></i><span>关注</span></a></div><div class="sticky_layout"></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">©2020 - 2022 By 王恒</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><a id="to_comment" href="#post-comment" title="直达评论"><i class="fas fa-comments"></i></a><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span> 数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div></div></div><div id="search-mask"></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.umd.min.js"></script><script src="https://cdn.jsdelivr.net/npm/instant.page/instantpage.min.js" type="module"></script><script src="https://cdn.jsdelivr.net/npm/vanilla-lazyload/dist/lazyload.iife.min.js"></script><script src="/js/search/local-search.js"></script><div class="js-pjax"><script>function loadDisqus () {
var disqus_config = function () {
this.page.url = 'http://wangheng.org/kuaipan-uploader-dev-share.html'
this.page.identifier = '/kuaipan-uploader-dev-share.html'
this.page.title = 'kuaipan_uploader开发分享'
};
window.disqusReset = () => {
DISQUS.reset({
reload: true,
config: disqus_config
})
}
if (window.DISQUS) disqusReset()
else {
(function() {
var d = document, s = d.createElement('script');
s.src = 'https://wangheng.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
}
document.getElementById('darkmode').addEventListener('click', () => {
setTimeout(() => window.disqusReset(), 200)
})
}
if ('Disqus' === 'Disqus' || !true) {
if (true) btf.loadComment(document.getElementById('disqus_thread'), loadDisqus)
else loadDisqus()
} else {
function loadOtherComment () {
loadDisqus()
}
}
</script></div><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div></body></html>