cul-handles 0.1.0 → 0.2.0

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.
@@ -0,0 +1,113 @@
1
+ module Cul
2
+ module Handles
3
+ class Client
4
+ include Hdl
5
+ DEFAULT_ADMIN = "10022/ADMIN"
6
+ def initialize(server,port,admin=DEFAULT_ADMIN)
7
+ @server = server
8
+ @port = port
9
+ @admin = admin
10
+ @debug = false
11
+ end
12
+ def debug=(val)
13
+ if(val)
14
+ @debug = true
15
+ else
16
+ @debug = false
17
+ end
18
+ end
19
+ def initRequest(request)
20
+ now = Time.new
21
+ request.requestId= now.to_i
22
+ request.expirationTime=(Time.new().to_i + 600) # 10 minutes
23
+ return request
24
+ end
25
+ def resolve(handle)
26
+ sock = TCPSocket.new(@server,@port)
27
+ req = ResolutionRequest.new(handle)
28
+ req.publicOnly=true
29
+ req.authoritative=true
30
+ req.keepAlive=false
31
+ req.siteInfoSerial=-1
32
+ req.sequenceNumber=1
33
+ now = Time.new
34
+ req.requestId=((now.to_i * 1000000) + (now.usec % 1000))
35
+ req.expirationTime=0
36
+ req.sessionId= 0 #get new res.sessionId
37
+ res = ResolutionResponse.new()
38
+ res.send(req,sock)
39
+ if (@debug)
40
+ puts "Resolution Request sent"
41
+ puts("used sessionId: " + res.sessionId.to_s + "; requestId: " + res.requestId.to_s)
42
+ puts("response code: " + res.responseCode.to_s)
43
+ end
44
+ sock.close()
45
+ return res
46
+ end
47
+ def createHandle(adminSecret,handle,url=nil)
48
+ req = Cul::Handles::CreateHandleRequest.new(handle)
49
+ initRequest(req)
50
+ req.addAdminValue(@admin, PERM_ALL, 100)
51
+ if not url.nil?
52
+ req.addURLValue(url)
53
+ end
54
+ return sendAuthRequest(req, adminSecret)
55
+ end
56
+ def createAdminHandle(adminSecret, newHandle, newHandleSecret)
57
+ req = Cul::Handles::CreateHandleRequest.new(newHandle)
58
+ initRequest(req)
59
+ req.addAdminValue(DEFAULT_ADMIN, PERM_ALL, 100)
60
+ req.addSecretKeyValue(newHandleSecret)
61
+ return sendAuthRequest(req, adminSecret)
62
+ end
63
+ def deleteHandle(adminSecret,handle)
64
+ req = Cul::Handles::DeleteHandleRequest.new(handle)
65
+ initRequest(req)
66
+ return sendAuthRequest(req, adminSecret)
67
+ end
68
+ def addHandleValue(adminSecret,handle,url)
69
+ req = Cul::Handles::AddValueRequest.new(handle)
70
+ req.addURLValue(url)
71
+ initRequest(req)
72
+ return sendAuthRequest(req, adminSecret)
73
+ end
74
+ def changeHandleValue(adminSecret, handle, url)
75
+ req = Cul::Handles::ModifyValueRequest.new(handle)
76
+ req.addURLValue(url)
77
+ initRequest(req)
78
+ return sendAuthRequest(req, adminSecret)
79
+ end
80
+ def addHandleMaintainer(adminSecret,handle,maintainerHandle)
81
+ req = Cul::Handles::AddValueRequest.new(handle)
82
+ req.addAdminValue(maintainerHandle, 0x0070, INDEX_MAINTAINER_HANDLE)
83
+ initRequest(req)
84
+ return sendAuthRequest(req, adminSecret)
85
+ end
86
+ def deleteHandleValue(adminSecret, handle, url)
87
+ req = Cul::Handles::DeleteValueRequest.new(handle)
88
+ req.addURLValue(url)
89
+ initRequest(req)
90
+ return sendAuthRequest(req, adminSecret)
91
+ end
92
+ def sendAuthRequest(request, adminSecret)
93
+ res = ChallengeResponse.new()
94
+ sock = TCPSocket.new(@server,@port)
95
+ res.send(request, sock)
96
+ sock.close()
97
+ if not (res.responseCode.eql?RC_AUTHEN_NEEDED)
98
+ raise "Unexpected server challenge rcode: " + res.responseCode.to_s
99
+ end
100
+ creq = ChallengeAnswerRequest.new(res.nonce,res.digest,@admin,INDEX_AUTH)
101
+ creq.sessionId = res.sessionId
102
+ initRequest(creq)
103
+ creq.requestId= request.requestId + 1
104
+ creq.secret=(adminSecret)
105
+ cres = BaseResponse.new()
106
+ sock = TCPSocket.new(@server,@port)
107
+ cres.send(creq, sock)
108
+ sock.close()
109
+ return cres
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,22 @@
1
+ module Cul
2
+ module Handles
3
+ class CreateHandleRequest < HandleValueRequest
4
+ def initialize(handle)
5
+ super()
6
+ @opCode = asBytes(Hdl::OC_CREATE_HANDLE)
7
+ end
8
+ def valid?
9
+ if not @handle
10
+ return false
11
+ end
12
+ @values.each { |value|
13
+ if value.type == "HS_ADMIN"
14
+ return true
15
+ end
16
+ }
17
+ return false
18
+ end
19
+ end
20
+ end
21
+ end
22
+
@@ -0,0 +1,22 @@
1
+ module Cul
2
+ module Handles
3
+ class DeleteHandleRequest < BaseRequest
4
+ include Hdl
5
+ def initialize(handle)
6
+ super()
7
+ @opCode = asBytes(Hdl::OC_DELETE_HANDLE)
8
+ self.responseCode = 0
9
+ @handle = toProtocolString(handle)
10
+ end
11
+ def valid?
12
+ if not @handle
13
+ return false
14
+ end
15
+ return true
16
+ end
17
+ def encodeBody
18
+ @body = @handle
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ module Cul
2
+ module Handles
3
+ class RemoveValueRequest < BaseRequest
4
+ include Hdl
5
+ def initialize(handle)
6
+ super()
7
+ @opCode = asBytes(OC_REMOVE_VALUE)
8
+ self.responseCode = 0
9
+ @handle = toProtocolString(handle)
10
+ @values = []
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,90 @@
1
+ module Cul
2
+ module Handles
3
+ class HandleValueRequest < BaseRequest
4
+ ADMIN_ONLY = HandleValue::PERM_ADMIN_READ & HandleValue::PERM_ADMIN_WRITE
5
+ def initialize(handle)
6
+ super()
7
+ self.responseCode = 0
8
+ self.certify=true
9
+ self.authoritative=true
10
+ self.returnRequestDigest=(true)
11
+ @handle = toProtocolString(handle)
12
+ @values = []
13
+ end
14
+ def addURLValue(urlValue)
15
+ # serialize handle value
16
+ value = HandleValue.new()
17
+ value.data = urlValue.unpack('U*')
18
+ value.type = "URL".unpack('U*')
19
+ value.index = asBytes(1) # is this a default?
20
+ @values.push(value)
21
+ end
22
+ def addAdminValue(adminHandle, permissions, index=INDEX_ADMIN_HANDLE)
23
+ value = HandleValue.new()
24
+ value.data=value.encodeAdminData(adminHandle, permissions, INDEX_AUTH)
25
+ value.type = "HS_ADMIN".unpack('U*')
26
+ value.index = asBytes(index) # is this a default?
27
+ @values.push(value)
28
+ end
29
+ def addSecretKeyValue(secret)
30
+ value = HandleValue.new()
31
+ value.data=secret.unpack('U*')
32
+
33
+ value.type="HS_SECKEY".unpack('U*')
34
+ value.perm=(ADMIN_ONLY)
35
+ value.index = asBytes(INDEX_AUTH)
36
+ @values.push(value)
37
+ end
38
+ def encodeBody
39
+ result = [].concat(@handle)
40
+ result.concat(asBytes(@values.length))
41
+ @values.each {|value|
42
+ #puts value.serialize.join unless value.nil?
43
+ result.concat(value.serialize)
44
+ }
45
+ @body = result
46
+ end
47
+ end
48
+ class CreateHandleRequest < HandleValueRequest
49
+ def initialize(handle)
50
+ super(handle)
51
+ @opCode = asBytes(Hdl::OC_CREATE_HANDLE)
52
+ end
53
+ def valid?
54
+ if not @handle
55
+ return false
56
+ end
57
+ @values.each { |value|
58
+ if value.type == "HS_ADMIN"
59
+ return true
60
+ end
61
+ }
62
+ return false
63
+ end
64
+ end
65
+ class AddValueRequest < HandleValueRequest
66
+ def initialize(handle)
67
+ super(handle)
68
+ @opCode = asBytes(Hdl::OC_ADD_VALUE)
69
+ end
70
+ end
71
+ class ModifyValueRequest < HandleValueRequest
72
+ def initialize(handle)
73
+ super(handle)
74
+ @opCode = asBytes(Hdl::OC_MODIFY_VALUE)
75
+ end
76
+ end
77
+ class DeleteValueRequest < HandleValueRequest
78
+ def initialize(handle)
79
+ super(handle)
80
+ @opCode = asBytes(Hdl::OC_REMOVE_VALUE)
81
+ end
82
+ def addAdminValue(adminHandle, permissions, index)
83
+ if (index.eql?(100))
84
+ raise "Deleting the admin value would leave the handle without an administrator; Use modify value instead."
85
+ end
86
+ super(adminHandle, permissions, index)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,244 @@
1
+ module Cul
2
+ module Handles
3
+ module Hdl
4
+ # OpFlag masks
5
+ MSG_FLAG_AUTH = 0x80 # don't use cache, use only primaries
6
+ MSG_FLAG_CERT = 0x40 # asks server to sign responses
7
+ MSG_FLAG_ENCR = 0x20 # asks server to encrypt responses
8
+ MSG_FLAG_RECU = 0x10 # server should try and resolve handle if not found
9
+ MSG_FLAG_CACR = 0x08 # responses should be signed by cache
10
+ MSG_FLAG_CONT = 0x04 # there are more parts to this message
11
+ MSG_FLAG_KPAL = 0x02 # keep the socket open for more requests
12
+ MSG_FLAG_PUBL = 0x01 # resolution requests should only return public vals
13
+ MSG_FLAG_RRDG = 0x80 # responses should include a digest of the request
14
+ MSG_FLAG_AUTH_INDEX = 0
15
+ MSG_FLAG_CERT_INDEX = 0
16
+ MSG_FLAG_ENCR_INDEX = 0
17
+ MSG_FLAG_RECU_INDEX = 0
18
+ MSG_FLAG_CACR_INDEX = 0
19
+ MSG_FLAG_CONT_INDEX = 0
20
+ MSG_FLAG_KPAL_INDEX = 0
21
+ MSG_FLAG_PUBL_INDEX = 0
22
+ MSG_FLAG_RRDG_INDEX = 1
23
+ # MessageFlag masks
24
+ ENV_FLAG_COMPRESSED = 0x80
25
+ ENV_FLAG_ENCRYPTED = 0x40
26
+ ENV_FLAG_TRUNCATED = 0x20
27
+ # OpCode values
28
+ OC_RESERVED = 0
29
+ OC_RESOLUTION = 1
30
+ OC_GET_SITEINFO = 2
31
+ OC_CREATE_HANDLE = 100
32
+ OC_DELETE_HANDLE = 101
33
+ OC_ADD_VALUE = 102
34
+ OC_REMOVE_VALUE = 103
35
+ OC_MODIFY_VALUE = 104
36
+ OC_LIST_HANDLE = 105
37
+ OC_LIST_NA = 106
38
+ OC_CHALLENGE_RESPONSE = 200
39
+ OC_VERIFY_RESPONSE = 201
40
+ OC_SESSION_SETUP = 400
41
+ OC_SESSION_TERMINATE = 401
42
+ OC_SESSION_EXCHANGEKEY = 402
43
+ # ResponseCode values
44
+ RC_RESERVED = 0
45
+ RC_SUCCESS = 1
46
+ RC_ERROR = 2
47
+ RC_SERVER_BUSY = 3
48
+ RC_PROTOCOL_ERROR = 4
49
+ RC_OPERATION_DENIED = 5
50
+ RC_RECUR_LIMIT_EXCEEDED = 6
51
+ RC_HANDLE_NOT_FOUND = 100
52
+ RC_HANDLE_ALREADY_EXIST = 101
53
+ RC_INVALID_HANDLE = 102
54
+ RC_VALUE_NOT_FOUND = 200
55
+ RC_VALUE_ALREADY_EXIST = 201
56
+ RC_VALUE_INVALID = 202
57
+ RC_EXPIRED_SITE_INFO = 300
58
+ RC_SERVER_NOT_RESP = 301
59
+ RC_SERVICE_REFERRAL = 302
60
+ RC_NA_DELEGATE = 303
61
+ RC_NOT_AUTHORIZED = 400
62
+ RC_ACCESS_DENIED = 401
63
+ RC_AUTHEN_NEEDED = 402
64
+ RC_AUTHEN_FAILED = 403
65
+ RC_INVALID_CREDENTIAL = 404
66
+ RC_AUTHEN_TIMEOUT = 405
67
+ RC_UNABLE_TO_AUTHEN = 406
68
+ RC_SESSION_TIMEOUT = 500
69
+ RC_SESSION_FAILED = 501
70
+ RC_NO_SESSION_KEY = 502
71
+ RC_SESSION_NO_SUPPORT = 503
72
+ RC_SESSION_KEY_INVALID = 504
73
+ RC_TRYING = 900
74
+ RC_FORWARDED = 901
75
+ RC_QUEUED = 902
76
+ # handle value admin permissions
77
+ PERM_ADD_HANDLE = 0x0001;
78
+ PERM_DELETE_HANDLE = 0x0002;
79
+ PERM_ADD_NA = 0x0004;
80
+ PERM_DELETE_NA = 0x0008;
81
+ PERM_MODIFY_VALUE = 0x0010;
82
+ PERM_REMOVE_VALUE = 0x0020;
83
+ PERM_ADD_VALUE = 0x0040;
84
+ PERM_MODIFY_ADMIN = 0x0080;
85
+ PERM_REMOVE_ADMIN = 0x0100;
86
+ PERM_ADD_ADMIN = 0x0200;
87
+ PERM_READ_VALUE = 0x0400;
88
+ PERM_LIST_HDLS = 0x0800;
89
+ PERM_ALL = 0x0fff;
90
+ # standard handle indices
91
+ INDEX_ADMIN_HANDLE = 100 # index for create/delete/super admin
92
+ INDEX_MAINTAINER_HANDLE = 101 # index for modify/update admin
93
+ INDEX_AUTH = 300 # index of HS_SECKEY value
94
+ class UnsignedInt
95
+ def UnsignedInt.asBytes(val)
96
+ [(val&0xff000000)>>24, (val&0xff0000)>>16, (val&0xff00)>>8, val&0xff]
97
+ end
98
+ def UnsignedInt.fromBytes(data)
99
+ result = data[-1]
100
+ for i in ((data.length-1)..1)
101
+ result |= (data[i] << (8*i))
102
+ end
103
+ return result
104
+ end
105
+ end
106
+ class UnsignedShort
107
+ def UnsignedShort.asBytes(val)
108
+ [(val&0xff00)>>8, val&0xff]
109
+ end
110
+ def UnsignedShort.fromBytes(data)
111
+ result = data[-1]
112
+ for i in ((data.length-1)..1)
113
+ result |= (data[i] << (8*i))
114
+ end
115
+ return result
116
+ end
117
+ end
118
+ class UnsignedByte
119
+ def UnsignedByte.asBytes(val)
120
+ [val&0xff]
121
+ end
122
+ def UnsignedByte.fromBytes(data)
123
+ if data.to_i == data
124
+ mask = data
125
+ else
126
+ mask = data[0]
127
+ end
128
+ result = 0
129
+ if mask & 0x01 == 0x01
130
+ result = result + 1
131
+ end
132
+ if mask & 0x02 == 0x02
133
+ result = result + 2
134
+ end
135
+ if mask & 0x04 == 0x04
136
+ result = result + 4
137
+ end
138
+ if mask & 0x08 == 0x08
139
+ result = result + 8
140
+ end
141
+ if mask & 0x10 == 0x10
142
+ result = result + 16
143
+ end
144
+ if mask & 0x20 == 0x20
145
+ result = result + 32
146
+ end
147
+ if mask & 0x40 == 0x40
148
+ result = result + 64
149
+ end
150
+ if mask & 0x80 == 0x80
151
+ result = result + 128
152
+ end
153
+ return result
154
+ end
155
+ end
156
+ def asBytes(val)
157
+ [(val&0xff000000)>>24,(val&0xff0000)>>16,(val&0xff00)>>8,val&0xff]
158
+ end
159
+ def fromBytes(data)
160
+ if(data.nil?)
161
+ return 0
162
+ end
163
+ result = 0
164
+ shift = data.length - 1
165
+ data.each{|byte|
166
+ digit = UnsignedByte.fromBytes(byte)
167
+ result = result + (digit << (8*shift))
168
+ shift = shift - 1
169
+ }
170
+ return result
171
+ end
172
+ def toProtocolString(data)
173
+ dataBytes = data.unpack('U*').pack('U*').unpack('C*')
174
+ length = dataBytes.length
175
+ result = asBytes(length)
176
+ result.concat(dataBytes)
177
+ return result
178
+ end
179
+ def readProtocolString(data,offset=0)
180
+ octetsRead = 4
181
+ length = fromBytes(data[offset...offset+4])
182
+ pstring = ""
183
+ if length > 0
184
+ pstring = data[offset+4...offset+4+length].pack('C*')
185
+ octetsRead = octetsRead + length
186
+ end
187
+ return [octetsRead,pstring]
188
+ end
189
+ def readByteArray(data,offset=0)
190
+ bytes = fromBytes(data[offset...offset+4])
191
+ octetsRead = 4 + bytes
192
+ start = offset + 4
193
+ result = data[start...(start+bytes)]
194
+ return [octetsRead,result]
195
+ end
196
+ def readIntArray(data,offset=0)
197
+ ints = fromBytes(data[offset...offset+4])
198
+ octetsRead = 4 + (4*ints)
199
+ start = offset + 4
200
+ result = data[start...(offset+octetsRead)]
201
+ return [octetsRead,result]
202
+ end
203
+ def calculateValueLen(values,offset=0)
204
+ origOffset = offset
205
+ offset = offset + 14 # index - 4 bytes; timestamp - 4 bytes; ttlType - 1 byte; ttl - 4 bytes; permissions - 1 byte
206
+
207
+ fieldLen = fromBytes( values[offset...offset+4]) # type field
208
+ offset = offset + 4 + fieldLen
209
+
210
+ fieldLen = fromBytes( values[offset...offset+4]) # data field
211
+ offset = offset + 4 + fieldLen
212
+
213
+ fieldLen = fromBytes( values[offset...offset+4]) # references (number of)
214
+ offset = offset + 4 + fieldLen
215
+
216
+ for i in (1..fieldLen) # each reference - hdl length + hdl + index
217
+ refLen = fromBytes( values[offset...offset+4])
218
+ offset = offset + 4 + refLen + 4
219
+ end
220
+ return offset - origOffset
221
+ end
222
+ def decodeAdminData(data)
223
+ permissions = fromBytes(data[0..1])
224
+ arrayInfo = readByteArray(data[2...-1])
225
+ offset = 2 + arrayInfo[0]
226
+ adminHandle = arrayInfo[1].pack('U*')
227
+ index = fromBytes(data[offset..offset+3])
228
+ return {'permissions' => permissions, 'handle' => adminHandle, 'index' => index}
229
+ end
230
+ def encodeAdminData(adminHandle, permissions, index)
231
+ result = asBytes(permissions)[2..3]
232
+ hbytes = adminHandle.unpack('U*')
233
+ result.concat(asBytes(hbytes.length))
234
+ result.concat(hbytes)
235
+ result.concat(asBytes(index))
236
+ result
237
+ end
238
+ def convert16t8(data)
239
+ # first split into bytes
240
+ []
241
+ end
242
+ end
243
+ end
244
+ end
@@ -0,0 +1,10 @@
1
+ module Cul
2
+ module Handles
3
+ class ModifyValueRequest < HandleValueRequest
4
+ def initialize(handle)
5
+ super()
6
+ @opCode = asBytes(Hdl::OC_MODIFY_VALUE)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,31 @@
1
+ module Cul
2
+ module Handles
3
+ class ResolutionRequest < BaseRequest
4
+ def initialize(handle)
5
+ super()
6
+ @opCode = asBytes(OC_RESOLUTION)
7
+ self.responseCode = 0
8
+ self.authoritative=false
9
+ self.returnRequestDigest=false
10
+ self.encrypt=false
11
+ self.publicOnly=false
12
+ self.certify=false
13
+ self.cacheCertify=true
14
+ self.recursive=true
15
+ self.continuous=false
16
+ self.keepAlive=false
17
+ self.expirationTime=0
18
+ @handle = toProtocolString(handle)
19
+ end
20
+ def encodeBody()
21
+ @body= [].concat(@handle).concat(self.indexList).concat(self.typeList)
22
+ end
23
+ def indexList
24
+ [0,0,0,0] # return all indices
25
+ end
26
+ def typeList
27
+ [0,0,0,0] # return all types
28
+ end
29
+ end
30
+ end
31
+ end