pastehub 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/README.md +32 -0
- data/Rakefile +146 -0
- data/VERSION.yml +4 -0
- data/bin/PastehubSync +107 -0
- data/bin/pastehubDump +114 -0
- data/bin/pastehubPost +63 -0
- data/lib/pastehub.rb +43 -0
- data/lib/pastehub/auth.rb +171 -0
- data/lib/pastehub/client.rb +453 -0
- data/lib/pastehub/clientsync.rb +287 -0
- data/lib/pastehub/clipboard.rb +56 -0
- data/lib/pastehub/config.rb +166 -0
- data/lib/pastehub/crypt.rb +70 -0
- data/lib/pastehub/localdb.rb +187 -0
- data/lib/pastehub/log.rb +95 -0
- data/lib/pastehub/macosx.rb +66 -0
- data/lib/pastehub/masterdb.rb +213 -0
- data/lib/pastehub/store.rb +83 -0
- data/lib/pastehub/util.rb +153 -0
- data/server/masterdb.rb +141 -0
- data/server/notifier.rb +89 -0
- metadata +235 -0
data/lib/pastehub.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#
|
2
|
+
# pastehub.rb - PasteHub's top-level library file
|
3
|
+
#
|
4
|
+
#
|
5
|
+
# Copyright (c) 2012 Kiyoka Nishiyama <kiyoka@sumibi.org>
|
6
|
+
#
|
7
|
+
# Redistribution and use in source and binary forms, with or without
|
8
|
+
# modification, are permitted provided that the following conditions
|
9
|
+
# are met:
|
10
|
+
#
|
11
|
+
# 1. Redistributions of source code must retain the above copyright
|
12
|
+
# notice, this list of conditions and the following disclaimer.
|
13
|
+
#
|
14
|
+
# 2. Redistributions in binary form must reproduce the above copyright
|
15
|
+
# notice, this list of conditions and the following disclaimer in the
|
16
|
+
# documentation and/or other materials provided with the distribution.
|
17
|
+
#
|
18
|
+
# 3. Neither the name of the authors nor the names of its contributors
|
19
|
+
# may be used to endorse or promote products derived from this
|
20
|
+
# software without specific prior written permission.
|
21
|
+
#
|
22
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
23
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
24
|
+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
25
|
+
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
26
|
+
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
27
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
28
|
+
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
29
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
30
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
31
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
32
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
#
|
34
|
+
#
|
35
|
+
require 'pastehub/config'
|
36
|
+
require 'pastehub/util'
|
37
|
+
require 'pastehub/crypt'
|
38
|
+
require 'pastehub/auth'
|
39
|
+
require 'pastehub/localdb'
|
40
|
+
require 'pastehub/store'
|
41
|
+
require 'pastehub/client'
|
42
|
+
require 'pastehub/clientsync'
|
43
|
+
require 'pastehub/clipboard'
|
@@ -0,0 +1,171 @@
|
|
1
|
+
#
|
2
|
+
# auth.rb - PasteHub's authentication library file
|
3
|
+
#
|
4
|
+
# Copyright (c) 2009-2011 Kiyoka Nishiyama <kiyoka@sumibi.org>
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions
|
8
|
+
# are met:
|
9
|
+
#
|
10
|
+
# 1. Redistributions of source code must retain the above copyright
|
11
|
+
# notice, this list of conditions and the following disclaimer.
|
12
|
+
#
|
13
|
+
# 2. Redistributions in binary form must reproduce the above copyright
|
14
|
+
# notice, this list of conditions and the following disclaimer in the
|
15
|
+
# documentation and/or other materials provided with the distribution.
|
16
|
+
#
|
17
|
+
# 3. Neither the name of the authors nor the names of its contributors
|
18
|
+
# may be used to endorse or promote products derived from this
|
19
|
+
# software without specific prior written permission.
|
20
|
+
#
|
21
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
22
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
23
|
+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
24
|
+
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
25
|
+
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
26
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
27
|
+
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
28
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
29
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
30
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
31
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
32
|
+
#
|
33
|
+
#
|
34
|
+
require "openssl"
|
35
|
+
require "base64"
|
36
|
+
require 'pp'
|
37
|
+
|
38
|
+
module PasteHub
|
39
|
+
MANDATORY_KEYS = [
|
40
|
+
'x-pastehub-username',
|
41
|
+
'x-pastehub-date',
|
42
|
+
'x-pastehub-version'
|
43
|
+
]
|
44
|
+
|
45
|
+
|
46
|
+
class Auth
|
47
|
+
def initialize()
|
48
|
+
@elements = Hash.new
|
49
|
+
end
|
50
|
+
|
51
|
+
def addElement( key, value )
|
52
|
+
@elements[key.downcase] = value
|
53
|
+
end
|
54
|
+
|
55
|
+
def calcSignature( secretKey )
|
56
|
+
a = Set.new( @elements.keys )
|
57
|
+
b = Set.new( MANDATORY_KEYS )
|
58
|
+
if a.superset?( b )
|
59
|
+
message = MANDATORY_KEYS.sort.map {|k|
|
60
|
+
k + ':' + @elements[k]
|
61
|
+
}.join( ',' ).downcase
|
62
|
+
|
63
|
+
h = OpenSSL::HMAC::digest(OpenSSL::Digest::SHA256.new, secretKey, message)
|
64
|
+
Base64.encode64(h).chomp
|
65
|
+
else
|
66
|
+
# not enough keys
|
67
|
+
:NotEnoughKeys
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def getAuthHash( )
|
72
|
+
@elements
|
73
|
+
end
|
74
|
+
|
75
|
+
def username()
|
76
|
+
@elements['x-pastehub-username']
|
77
|
+
end
|
78
|
+
|
79
|
+
def curTime()
|
80
|
+
@elements['x-pastehub-date']
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class AuthForClient
|
85
|
+
def initialize( username, secretKey )
|
86
|
+
util = Util.new
|
87
|
+
@token = Auth.new( )
|
88
|
+
@token.addElement( 'x-pastehub-username', username )
|
89
|
+
@token.addElement( 'x-pastehub-date', util.key_seconds( util.currentTime( )).to_s )
|
90
|
+
@token.addElement( 'x-pastehub-version', '2012-06-16' )
|
91
|
+
@secretKey = secretKey
|
92
|
+
end
|
93
|
+
|
94
|
+
def getAuthHash( )
|
95
|
+
sign = @token.calcSignature( @secretKey )
|
96
|
+
#pp ["sign", sign ]
|
97
|
+
if sign.is_a? String
|
98
|
+
@token.addElement( 'Authorization', sign )
|
99
|
+
@token.getAuthHash()
|
100
|
+
else
|
101
|
+
raise RuntimeError, "Error: can't create AuthForClient instance."
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# for Testing with RSpec.
|
106
|
+
def _addElement( key, value )
|
107
|
+
@token.addElement( key, value )
|
108
|
+
end
|
109
|
+
|
110
|
+
def username()
|
111
|
+
@token.username
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class AuthForServer
|
116
|
+
def initialize( users )
|
117
|
+
# db connecter of Users table
|
118
|
+
@users = users
|
119
|
+
end
|
120
|
+
|
121
|
+
def expired?( clientTime, serverTime )
|
122
|
+
(60*5) < ( clientTime.to_i - serverTime.to_i ).abs
|
123
|
+
end
|
124
|
+
|
125
|
+
# return:
|
126
|
+
# [ true/false, "username", :reason ]
|
127
|
+
def invoke( hash, serverTime )
|
128
|
+
auth = Auth.new
|
129
|
+
client_sign = ""
|
130
|
+
hash.each { |k,v|
|
131
|
+
k = k.downcase
|
132
|
+
#pp [ "invoke", k, v ]
|
133
|
+
if MANDATORY_KEYS.include?( k )
|
134
|
+
auth.addElement( k, v )
|
135
|
+
end
|
136
|
+
if 'authorization' == k
|
137
|
+
client_sign = v
|
138
|
+
end
|
139
|
+
}
|
140
|
+
|
141
|
+
#pp [ "auth.getAuthHash()", auth.getAuthHash() ]
|
142
|
+
#pp [ "client_sign", client_sign ]
|
143
|
+
#pp [ "auth.username", auth.username ]
|
144
|
+
|
145
|
+
if not auth.username
|
146
|
+
# fail... username was unspecified
|
147
|
+
[ false, 'UNSPECIFIED', :unspecified_user ]
|
148
|
+
else
|
149
|
+
if @users.getSecretKey(auth.username)
|
150
|
+
server_sign = auth.calcSignature( @users.getSecretKey(auth.username) )
|
151
|
+
#pp [ "server_sign", server_sign ]
|
152
|
+
if server_sign == client_sign
|
153
|
+
|
154
|
+
if expired?( auth.curTime, serverTime )
|
155
|
+
# authentication success
|
156
|
+
[ false, auth.username, :expired_client_request ]
|
157
|
+
else
|
158
|
+
[ true, auth.username, :ok ]
|
159
|
+
end
|
160
|
+
else
|
161
|
+
# fail...
|
162
|
+
[ false, auth.username, :illegal_signature ]
|
163
|
+
end
|
164
|
+
else
|
165
|
+
# unknown user
|
166
|
+
[ false, auth.username, :unknown_user ]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,453 @@
|
|
1
|
+
#
|
2
|
+
# client.rb - PasteHub's client main library
|
3
|
+
#
|
4
|
+
# Copyright (c) 2009-2011 Kiyoka Nishiyama <kiyoka@sumibi.org>
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions
|
8
|
+
# are met:
|
9
|
+
#
|
10
|
+
# 1. Redistributions of source code must retain the above copyright
|
11
|
+
# notice, this list of conditions and the following disclaimer.
|
12
|
+
#
|
13
|
+
# 2. Redistributions in binary form must reproduce the above copyright
|
14
|
+
# notice, this list of conditions and the following disclaimer in the
|
15
|
+
# documentation and/or other materials provided with the distribution.
|
16
|
+
#
|
17
|
+
# 3. Neither the name of the authors nor the names of its contributors
|
18
|
+
# may be used to endorse or promote products derived from this
|
19
|
+
# software without specific prior written permission.
|
20
|
+
#
|
21
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
22
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
23
|
+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
24
|
+
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
25
|
+
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
26
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
27
|
+
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
28
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
29
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
30
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
31
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
32
|
+
#
|
33
|
+
#
|
34
|
+
require 'net/http'
|
35
|
+
require 'net/https'
|
36
|
+
require 'uri'
|
37
|
+
require 'open-uri'
|
38
|
+
require 'fileutils'
|
39
|
+
|
40
|
+
module PasteHub
|
41
|
+
|
42
|
+
def self.signfilePath
|
43
|
+
signfile = PasteHub::Config.instance.localDbPath + "authinfo.txt"
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.loadUsername
|
47
|
+
signfile = self.signfilePath
|
48
|
+
|
49
|
+
# load authenticate information
|
50
|
+
if not File.exist?( signfile )
|
51
|
+
return nil
|
52
|
+
else
|
53
|
+
begin
|
54
|
+
open( signfile ) {|f|
|
55
|
+
# first line is email (is username)
|
56
|
+
username = f.readline.chomp
|
57
|
+
if username.match( /^[a-z]+/ )
|
58
|
+
return username
|
59
|
+
end
|
60
|
+
}
|
61
|
+
rescue Exception => e
|
62
|
+
STDERR.puts( "Error: can't load #{signfile}: #{e.to_s}" )
|
63
|
+
raise e
|
64
|
+
end
|
65
|
+
return nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# setup user's directory
|
70
|
+
# result: true ... success / false ... fail
|
71
|
+
def self.setupDirectory
|
72
|
+
localdb_path = PasteHub::Config.instance.localDbPath
|
73
|
+
# Create directory
|
74
|
+
if not File.exist?( localdb_path )
|
75
|
+
if 0 == Dir.mkdir( localdb_path, 0700 )
|
76
|
+
STDERR.puts( "Info: created directory #{localdb_path}" )
|
77
|
+
else
|
78
|
+
STDERR.puts( "Error: can't create directory #{localdb_path}" )
|
79
|
+
return false
|
80
|
+
end
|
81
|
+
end
|
82
|
+
return true
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.signIn
|
86
|
+
signfile = self.signfilePath
|
87
|
+
util = Util.new
|
88
|
+
|
89
|
+
# authenticate information
|
90
|
+
if not File.exist?( signfile )
|
91
|
+
3.times { |n|
|
92
|
+
util.say( "Please input your account information" )
|
93
|
+
username = util.inputText(" email: ")
|
94
|
+
secretKey = util.inputText(" secret-key: " )
|
95
|
+
auth = AuthForClient.new( username, secretKey )
|
96
|
+
client = Client.new( auth )
|
97
|
+
if client.authTest()
|
98
|
+
# save authinfo with gpg
|
99
|
+
begin
|
100
|
+
password = util.inputPasswordTwice(
|
101
|
+
"Please input password for crypted file",
|
102
|
+
" password : ",
|
103
|
+
" password(for verify): " )
|
104
|
+
if password
|
105
|
+
crypt = PasteHub::Crypt.new( password )
|
106
|
+
open( signfile, "w" ) {|f|
|
107
|
+
f.puts( username )
|
108
|
+
f.puts( crypt.en( secretKey ))
|
109
|
+
}
|
110
|
+
# auth OK
|
111
|
+
return [ username, secretKey, password ]
|
112
|
+
end
|
113
|
+
STDERR.puts( "Error: password setting failed..." )
|
114
|
+
rescue Exception => e
|
115
|
+
STDERR.puts( "Error: can't save #{signfile}: #{e.to_s}" )
|
116
|
+
end
|
117
|
+
else
|
118
|
+
STDERR.puts( "your email or secret key is not registerd..." )
|
119
|
+
end
|
120
|
+
}
|
121
|
+
else
|
122
|
+
begin
|
123
|
+
open( signfile ) {|f|
|
124
|
+
util.say( "Please input password for crypted file" )
|
125
|
+
username = f.readline.chomp
|
126
|
+
signStr = f.read
|
127
|
+
3.times { |n|
|
128
|
+
password = util.inputPassword(" crypt password: ")
|
129
|
+
crypt = PasteHub::Crypt.new( password )
|
130
|
+
secretKey= crypt.de( signStr )
|
131
|
+
if secretKey
|
132
|
+
auth = AuthForClient.new( username, secretKey )
|
133
|
+
client = Client.new( auth )
|
134
|
+
if client.authTest()
|
135
|
+
return [ username, secretKey, password ]
|
136
|
+
else
|
137
|
+
STDERR.puts( "Error: your secretKey may be old." )
|
138
|
+
end
|
139
|
+
end
|
140
|
+
STDERR.puts( "Error: missing password." )
|
141
|
+
}
|
142
|
+
}
|
143
|
+
rescue Exception => e
|
144
|
+
STDERR.puts( "Error: can't load #{signfile}: #{e.to_s}" )
|
145
|
+
raise e
|
146
|
+
end
|
147
|
+
end
|
148
|
+
return [ nil, nil, nil ]
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.savePid( pid )
|
152
|
+
pidFile = PasteHub::Config.instance.localDbPath + "pid"
|
153
|
+
open( pidFile, "w" ) {|f|
|
154
|
+
f.puts pid
|
155
|
+
}
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.loadPid
|
159
|
+
pidFile = PasteHub::Config.instance.localDbPath + "pid"
|
160
|
+
pid = 0
|
161
|
+
begin
|
162
|
+
pid = open( pidFile ) {|f|
|
163
|
+
f.readline.chomp.to_i
|
164
|
+
}
|
165
|
+
rescue Exception => e
|
166
|
+
STDERR.puts( "Warning: can't load #{pidFile}: #{e.to_s}" )
|
167
|
+
pid = 0
|
168
|
+
end
|
169
|
+
return pid
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
class ClientBase
|
174
|
+
|
175
|
+
# return: Net::HTTPResponse
|
176
|
+
def httpGet( uriStr, headerHash, errorMessage )
|
177
|
+
uri = URI.parse( uriStr )
|
178
|
+
begin
|
179
|
+
https = Net::HTTP.new(uri.host, uri.port)
|
180
|
+
if ( Net::HTTP.https_default_port == uri.port ) or ( "https" == uri.scheme )
|
181
|
+
https.use_ssl = true
|
182
|
+
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
183
|
+
end
|
184
|
+
https.start {|http|
|
185
|
+
resp = http.get(uri.request_uri, headerHash)
|
186
|
+
if "200" == resp.code
|
187
|
+
return resp
|
188
|
+
end
|
189
|
+
}
|
190
|
+
rescue Exception => e
|
191
|
+
STDERR.puts errorMessage + ":" + e.to_s
|
192
|
+
end
|
193
|
+
return nil
|
194
|
+
end
|
195
|
+
|
196
|
+
# return: Net::HTTPResponse
|
197
|
+
def httpPost( uriStr, bodyStr, headerHash, errorMessage )
|
198
|
+
uri = URI.parse( uriStr )
|
199
|
+
begin
|
200
|
+
https = Net::HTTP.new(uri.host, uri.port)
|
201
|
+
if ( Net::HTTP.https_default_port == uri.port ) or ( "https" == uri.scheme )
|
202
|
+
https.use_ssl = true
|
203
|
+
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
204
|
+
end
|
205
|
+
https.start {|http|
|
206
|
+
resp = http.post(uri.request_uri, bodyStr, headerHash)
|
207
|
+
if "200" == resp.code
|
208
|
+
return resp
|
209
|
+
end
|
210
|
+
}
|
211
|
+
rescue Exception => e
|
212
|
+
STDERR.puts errorMessage + ":" + e.to_s
|
213
|
+
end
|
214
|
+
return nil
|
215
|
+
end
|
216
|
+
|
217
|
+
# return: [ Net::HTTP, Net::HTTP::Get ]
|
218
|
+
def httpGetRequest( uriStr, headerHash, errorMessage )
|
219
|
+
uri = URI.parse( uriStr )
|
220
|
+
begin
|
221
|
+
https = Net::HTTP.new(uri.host, uri.port)
|
222
|
+
if ( Net::HTTP.https_default_port == uri.port ) or ( "https" == uri.scheme )
|
223
|
+
https.use_ssl = true
|
224
|
+
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
225
|
+
end
|
226
|
+
return [ https, Net::HTTP::Get.new(uri.request_uri, headerHash) ]
|
227
|
+
rescue Exception => e
|
228
|
+
STDERR.puts errorMessage + ":" + e.to_s
|
229
|
+
end
|
230
|
+
return nil
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
class Client < ClientBase
|
237
|
+
def initialize( auth, password = nil )
|
238
|
+
@auth = auth
|
239
|
+
ins = PasteHub::Config.instance
|
240
|
+
@localdb_path = ins.localDbPath
|
241
|
+
@server_api_url = ins.targetApiURL
|
242
|
+
@server_notifier_url = ins.targetNotifierURL
|
243
|
+
@list_items = ins.listItems
|
244
|
+
@syncTrigger = []
|
245
|
+
@crypt = if password
|
246
|
+
Crypt.new( password )
|
247
|
+
else
|
248
|
+
nil
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def authTest
|
253
|
+
httpGet( "#{@server_api_url}authTest", @auth.getAuthHash(), "Error: can't connect to server for auth test" )
|
254
|
+
end
|
255
|
+
|
256
|
+
|
257
|
+
def getList( limit = nil )
|
258
|
+
h = {"content-type" => "plain/text"}
|
259
|
+
if limit
|
260
|
+
h[ 'X-Pastehub-Limit' ] = limit.to_i
|
261
|
+
end
|
262
|
+
|
263
|
+
resp = httpGet( "#{@server_api_url}getList", @auth.getAuthHash().merge( h ), "Error: fails 'getList' from server." )
|
264
|
+
str = resp.read_body()
|
265
|
+
masterList = str.split( /\n/ )
|
266
|
+
STDERR.puts "Info: masterList lines = #{masterList.size} #{str.size}Bytes"
|
267
|
+
masterList = masterList.select { |x|
|
268
|
+
okSize = "1340542369=2012-06-24.12:52:49=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".size
|
269
|
+
if okSize != x.size
|
270
|
+
STDERR.puts "Info: masterList(NG): " + x
|
271
|
+
false
|
272
|
+
else
|
273
|
+
x
|
274
|
+
end
|
275
|
+
}
|
276
|
+
masterList
|
277
|
+
end
|
278
|
+
|
279
|
+
def getValue( key )
|
280
|
+
raise RuntimeError, "Error: no encrypt password." unless @crypt
|
281
|
+
|
282
|
+
resp = httpPost( "#{@server_api_url}getValue", key, @auth.getAuthHash().merge( {"content-type" => "plain/text"} ), "Error: fails 'getValue' from server." )
|
283
|
+
ret = @crypt.de( resp.read_body() )
|
284
|
+
unless ret
|
285
|
+
STDERR.puts( "Warning: encrypt password is wrong. getValue missing..." )
|
286
|
+
ret = "error..."
|
287
|
+
end
|
288
|
+
ret
|
289
|
+
end
|
290
|
+
|
291
|
+
def putValue( key, data )
|
292
|
+
ret = ""
|
293
|
+
if not key
|
294
|
+
key = "_"
|
295
|
+
end
|
296
|
+
raise RuntimeError, "Error: no encrypt password." unless @crypt
|
297
|
+
_data = @crypt.en( data )
|
298
|
+
unless _data
|
299
|
+
STDERR.puts( "Warning: encrypt password is wrong. putValue missing..." )
|
300
|
+
ret = nil
|
301
|
+
else
|
302
|
+
resp = httpPost( "#{@server_api_url}putValue", _data,
|
303
|
+
@auth.getAuthHash().merge(
|
304
|
+
{
|
305
|
+
"content-type" => "plain/text",
|
306
|
+
"x-pastehub-key" => key }),
|
307
|
+
"Error: fails 'putValue' from server." )
|
308
|
+
if resp
|
309
|
+
ret = resp.read_body()
|
310
|
+
end
|
311
|
+
end
|
312
|
+
ret
|
313
|
+
end
|
314
|
+
|
315
|
+
def wait_notify( auth )
|
316
|
+
begin
|
317
|
+
pair = httpGetRequest("#{@server_notifier_url}", auth.getAuthHash(), "Error: fails 'notifier' api on server." )
|
318
|
+
https = pair[0]
|
319
|
+
getRequest = pair[1]
|
320
|
+
https.start() { |http|
|
321
|
+
http.request(getRequest) do |response|
|
322
|
+
raise 'Response is not chuncked' unless response.chunked?
|
323
|
+
response.read_body do |chunk|
|
324
|
+
serverValue = chunk.chomp
|
325
|
+
if serverHasNew?( serverValue )
|
326
|
+
puts "Info: server has new data: #{serverValue}"
|
327
|
+
return chunk.chomp.clone()
|
328
|
+
else
|
329
|
+
puts "Info: server is stable: #{serverValue}"
|
330
|
+
end
|
331
|
+
if localHasNew?( )
|
332
|
+
puts "Info: local has new data"
|
333
|
+
return :local
|
334
|
+
end
|
335
|
+
end
|
336
|
+
if "200" != response.code
|
337
|
+
STDERR.puts "Error: request error result=[#{response.code}]"
|
338
|
+
return :retry
|
339
|
+
end
|
340
|
+
end
|
341
|
+
}
|
342
|
+
rescue EOFError => e
|
343
|
+
STDERR.puts "Error: disconnected by server."
|
344
|
+
return :retry
|
345
|
+
rescue Errno::ECONNREFUSED => e
|
346
|
+
STDERR.puts "Error: can't connect to server(ConnectionRefused)."
|
347
|
+
return :retry
|
348
|
+
rescue SocketError => e
|
349
|
+
STDERR.puts "Error: can't connect to server(SocketError)."
|
350
|
+
return :retry
|
351
|
+
rescue Errno::ETIMEDOUT => e
|
352
|
+
STDERR.puts "Error: can't connect to server(Timeout1)."
|
353
|
+
return :retry
|
354
|
+
rescue Timeout::Error => e
|
355
|
+
# ONLINE and notifier has no INFO.
|
356
|
+
return :timeout
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
def serverHasNew?( serverValue )
|
361
|
+
# open local db
|
362
|
+
localdb = PasteHub::LocalDB.new( @localdb_path )
|
363
|
+
localdb.open( @auth.username )
|
364
|
+
localValue = localdb.getValue( PasteHub::SERVER_DATE_KEY )
|
365
|
+
ret = (localValue != serverValue)
|
366
|
+
if ret
|
367
|
+
localdb.insertValue( PasteHub::SERVER_DATE_KEY, serverValue )
|
368
|
+
end
|
369
|
+
localdb.close()
|
370
|
+
return ret
|
371
|
+
end
|
372
|
+
|
373
|
+
def localHasNew?( )
|
374
|
+
localdb = PasteHub::LocalDB.new( @localdb_path )
|
375
|
+
localdb.open( @auth.username )
|
376
|
+
localValue = localdb.getValue( PasteHub::LOCAL_DATE_KEY )
|
377
|
+
serverValue = localdb.getValue( PasteHub::SERVER_DATE_KEY )
|
378
|
+
ret = if localValue and serverValue
|
379
|
+
(localValue > serverValue)
|
380
|
+
else
|
381
|
+
false
|
382
|
+
end
|
383
|
+
if ret
|
384
|
+
localdb.insertValue( PasteHub::LOCAL_DATE_KEY, serverValue )
|
385
|
+
end
|
386
|
+
localdb.close()
|
387
|
+
return ret
|
388
|
+
end
|
389
|
+
|
390
|
+
def setOnlineState( online )
|
391
|
+
# open local db
|
392
|
+
if online
|
393
|
+
if online?() == false
|
394
|
+
@syncTrigger.unshift( true )
|
395
|
+
end
|
396
|
+
end
|
397
|
+
localdb = PasteHub::LocalDB.new( @localdb_path )
|
398
|
+
localdb.open( @auth.username )
|
399
|
+
localdb.insertValue( PasteHub::ONLINE_STATE_KEY, online ? "1" : "0" )
|
400
|
+
localdb.close()
|
401
|
+
end
|
402
|
+
|
403
|
+
def online?( )
|
404
|
+
# open local db
|
405
|
+
localdb = PasteHub::LocalDB.new( @localdb_path )
|
406
|
+
localdb.open( @auth.username, true )
|
407
|
+
# printf( "[%s]", localdb.getValue( PasteHub::ONLINE_STATE_KEY ))
|
408
|
+
ret = ("1" == localdb.getValue( PasteHub::ONLINE_STATE_KEY ))
|
409
|
+
localdb.close()
|
410
|
+
ret
|
411
|
+
end
|
412
|
+
|
413
|
+
def getTrigger()
|
414
|
+
if 0 < @syncTrigger.size
|
415
|
+
return @syncTrigger.pop
|
416
|
+
end
|
417
|
+
return false
|
418
|
+
end
|
419
|
+
|
420
|
+
def localSaveValue( argKey = nil, data )
|
421
|
+
# open local db
|
422
|
+
util = PasteHub::Util.new( )
|
423
|
+
if argKey
|
424
|
+
key = argKey
|
425
|
+
else
|
426
|
+
key = util.currentTime( ) + "=" + util.digest( data )
|
427
|
+
end
|
428
|
+
|
429
|
+
localdb = PasteHub::LocalDB.new( @localdb_path )
|
430
|
+
localdb.open( @auth.username )
|
431
|
+
list = localdb.getList( )
|
432
|
+
if util.key_digest( list[0] ) == util.digest( data )
|
433
|
+
# duplicate
|
434
|
+
localdb.close()
|
435
|
+
list[0]
|
436
|
+
else
|
437
|
+
localdb.insertValue( key, data.dup )
|
438
|
+
localdb.insertValue( PasteHub::LOCAL_DATE_KEY, util.currentTime( ) )
|
439
|
+
localdb.close()
|
440
|
+
key
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
def setServerFlags( keys )
|
445
|
+
localdb = PasteHub::LocalDB.new( @localdb_path )
|
446
|
+
localdb.open( @auth.username )
|
447
|
+
keys.each { |key|
|
448
|
+
localdb.setServerFlag( key )
|
449
|
+
}
|
450
|
+
localdb.close()
|
451
|
+
end
|
452
|
+
end
|
453
|
+
end
|