vacman_controller 0.2.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 3d98133ea201d0ae3720517f298c719979a91fee
4
- data.tar.gz: 1c6ae1f43a4cc27ff8285073ea9d789c0b5c6c62
2
+ SHA256:
3
+ metadata.gz: 5ddbe7c0b1cf7bc1f64efa3ffa86ea66925dbdb27afa2f68434f0acfd3493fb8
4
+ data.tar.gz: cf653c109a8ba1bebdae0ecbdef5662978a05e56bfab0ee8a9f223ebc922d6fc
5
5
  SHA512:
6
- metadata.gz: 6c7e8cec7e94fab24bad7188374685263192721cf70ba66e751ef73e25dd24dbe0baaaed9e46b7a8d2e5fcc1e9f5055c4058857f85bf458e28297093312948e1
7
- data.tar.gz: 862c00c0d793e934d9bdb88af6bd7f06ac5cae8264a77a63afd84563f4c642fa9c65a8f5373083fb7e0c4edfa0f126e890f460e2992a147eb7daa4518a09dd88
6
+ metadata.gz: e81eed72afeda1a0d31053e55cc3eeaa7274e6324f02f8eb528361edd285e61a9a5e15b6a0de21abc8a1659c143f8dfcc93a449c6ebfa61f55e1cbf3aee2b13c
7
+ data.tar.gz: 97857b1596694fd6d40ff34aa8aad9b88b273b62fe69e2c5d90320c83fd21772599add8ce3f69a8e6094f5b03eed4d90c568fc78c923f9313951b71c8655f9a0
@@ -17,8 +17,8 @@ append_cflags "-I#{VACMAN_CONTROLLER}/include -Wall -std=c99 -Wno-declaration-af
17
17
  append_ldflags "-L#{VACMAN_CONTROLLER}/lib -laal2sdk -Wl,-rpath #{VACMAN_CONTROLLER}/lib"
18
18
 
19
19
  if find_library('aal2sdk', 'AAL2DPXInit', "#{VACMAN_CONTROLLER}/lib")
20
- create_makefile('vacman_controller/vacman_controller')
21
- else
20
+ create_makefile('vacman_controller/low_level')
21
+ else
22
22
  puts "No libaal2sdk found"
23
23
  exit 1
24
24
  end
@@ -1,60 +1,79 @@
1
+ /*
2
+ * Vacman Controller wrapper
3
+ *
4
+ * This Ruby Extension wraps the VASCO Vacman Controller
5
+ * library and makes its API accessible to Ruby code.
6
+ *
7
+ * (C) 2013 https://github.com/mlankenau
8
+ * (C) 2019 m.barnaba@ifad.org
9
+ */
10
+
1
11
  #include <ruby.h>
2
12
  #include <string.h>
3
13
  #include <aal2sdk.h>
4
14
 
5
- static VALUE e_vacmanerror; // our ruby exception type
6
- TKernelParms KernelParms; // Kernel Params
15
+
16
+ /* The Vacman default kernel parameters, set up upon extension initialisation. */
17
+ TKernelParms g_KernelParms;
18
+
19
+ /* Ruby exception type, defined as VacmanController::Error in Ruby land. */
20
+ static VALUE e_VacmanError;
21
+
7
22
 
8
23
  /*
9
- * raise an error and tell wich method failed with wich error code
24
+ * Raises an Error, decoding the Vacman Controller error code.
10
25
  */
11
- static void vacman_raise_error(const char* method, int error_code) {
12
- aat_ascii error_message[100];
13
- AAL2GetErrorMsg (error_code, error_message);
14
- rb_raise(e_vacmanerror, "%s error %d: %s", method, error_code, error_message);
26
+ static void vacman_library_error(const char* method, int vacman_error_code) {
27
+ aat_ascii vacman_error_message[100]; // Recommended value in documentation.
28
+
29
+ AAL2GetErrorMsg(vacman_error_code, vacman_error_message);
30
+
31
+ char error_message[256];
32
+ snprintf(error_message, 255, "%s error %d: %s", method, vacman_error_code,
33
+ vacman_error_message);
34
+
35
+ VALUE exc = rb_exc_new2(e_VacmanError, error_message);
36
+ rb_iv_set(exc, "@library_method", rb_str_new2(method));
37
+ rb_iv_set(exc, "@error_code", INT2FIX(vacman_error_code));
38
+ rb_iv_set(exc, "@error_message", rb_str_new2(vacman_error_message));
39
+
40
+ rb_exc_raise(exc);
15
41
  }
16
42
 
17
43
 
18
44
  /*
19
- * convert a ruby hash to TDigipassBlob structure
45
+ * Use AAL2GetLibraryVersion to obtain library version and return it as a Ruby Hash
20
46
  */
21
- static VALUE rbhash_get_key(VALUE token, const char *property, int type) {
22
- VALUE ret = rb_hash_aref(token, rb_str_new2(property));
47
+ static VALUE vacman_library_version(VALUE module) {
48
+ aat_ascii version[16];
49
+ aat_int32 version_len = sizeof(version);
23
50
 
24
- if (ret == Qnil) {
25
- rb_raise(e_vacmanerror, "invalid token object given: %s property is nil", property);
26
- return Qnil;
27
- }
51
+ aat_ascii bitness[4];
52
+ aat_int32 bitness_len = sizeof(bitness);
28
53
 
29
- if (!RB_TYPE_P(ret, type)) {
30
- rb_raise(e_vacmanerror, "invalid token object given: %s property is not of the correct type", property);
31
- return Qnil;
32
- }
54
+ aat_ascii type[8];
55
+ aat_int32 type_len = sizeof(type);
33
56
 
34
- return ret;
35
- }
57
+ aat_int32 result = AAL2GetLibraryVersion(version, &version_len, bitness,
58
+ &bitness_len, type, &type_len);
36
59
 
37
- static void rbhash_to_digipass(VALUE token, TDigipassBlob* dpdata) {
38
- if (!RB_TYPE_P(token, T_HASH)) {
39
- rb_raise(e_vacmanerror, "invalid token object given, requires an hash");
40
- return;
60
+ if (result != 0) {
61
+ vacman_library_error("AAL2GetLibraryVersion", result);
62
+ return Qnil;
41
63
  }
42
64
 
43
- VALUE blob = rbhash_get_key(token, "blob", T_STRING);
44
- VALUE serial = rbhash_get_key(token, "serial", T_STRING);
45
- VALUE app_name = rbhash_get_key(token, "app_name", T_STRING);
46
- VALUE flag1 = rbhash_get_key(token, "flags1", T_FIXNUM);
47
- VALUE flag2 = rbhash_get_key(token, "flags2", T_FIXNUM);
48
-
49
- memset(dpdata, 0, sizeof(*dpdata));
65
+ VALUE hash = rb_hash_new();
66
+ rb_hash_aset(hash, rb_str_new2("version"), rb_str_new2(version));
67
+ rb_hash_aset(hash, rb_str_new2("bitness"), rb_str_new2(bitness));
68
+ rb_hash_aset(hash, rb_str_new2("type"), rb_str_new2(type));
50
69
 
51
- strcpy(dpdata->Blob, rb_string_value_cstr(&blob));
52
- strncpy(dpdata->Serial, rb_string_value_cstr(&serial), sizeof(dpdata->Serial));
53
- strncpy(dpdata->AppName, rb_string_value_cstr(&app_name), sizeof(dpdata->AppName));
54
- dpdata->DPFlags[0] = rb_fix2int(flag1);
55
- dpdata->DPFlags[1] = rb_fix2int(flag2);
70
+ return hash;
56
71
  }
57
72
 
73
+
74
+ /*
75
+ * Convert a TDigipassBlob structure into a Ruby Hash
76
+ */
58
77
  static void digipass_to_rbhash(TDigipassBlob* dpdata, VALUE hash) {
59
78
  char buffer[256];
60
79
 
@@ -74,39 +93,62 @@ static void digipass_to_rbhash(TDigipassBlob* dpdata, VALUE hash) {
74
93
  rb_hash_aset(hash, rb_str_new2("flags2"), rb_fix_new(dpdata->DPFlags[1]));
75
94
  }
76
95
 
96
+
77
97
  /*
78
- * Get library version and return it as an hash
98
+ * Gets the given property from the given token hash and raises an Error
99
+ * if the following conditions occur:
100
+ *
101
+ * * The key is not found
102
+ * * The key is not of the given type
103
+ *
104
+ * Otherwise, the value corresponding to the key is returned.
105
+ *
79
106
  */
80
- static VALUE vacman_library_version(VALUE module) {
81
- aat_ascii version[16];
82
- aat_int32 version_len = sizeof(version);
107
+ static VALUE rbhash_get_key(VALUE token, const char *property, int type) {
108
+ VALUE ret = rb_hash_aref(token, rb_str_new2(property));
83
109
 
84
- aat_ascii bitness[4];
85
- aat_int32 bitness_len = sizeof(bitness);
110
+ if (ret == Qnil) {
111
+ rb_raise(e_VacmanError, "invalid token object given: %s property is nil", property);
112
+ return Qnil;
113
+ }
86
114
 
87
- aat_ascii type[8];
88
- aat_int32 type_len = sizeof(type);
115
+ if (!RB_TYPE_P(ret, type)) {
116
+ rb_raise(e_VacmanError, "invalid token object given: %s property is not of the correct type", property);
117
+ return Qnil;
118
+ }
89
119
 
90
- aat_int32 result = AAL2GetLibraryVersion(version, &version_len, bitness,
91
- &bitness_len, type, &type_len);
120
+ return ret;
121
+ }
92
122
 
93
- if (result != 0) {
94
- vacman_raise_error("AAL2GetLibraryVersion", result);
95
- return Qnil;
123
+
124
+ /*
125
+ * Convert a Ruby Hash with the required keys to a TDigipassBlob structure.
126
+ */
127
+ static void rbhash_to_digipass(VALUE token, TDigipassBlob* dpdata) {
128
+ if (!RB_TYPE_P(token, T_HASH)) {
129
+ rb_raise(e_VacmanError, "invalid token object given, requires an hash");
130
+ return;
96
131
  }
97
132
 
98
- VALUE hash = rb_hash_new();
99
- rb_hash_aset(hash, rb_str_new2("version"), rb_str_new2(version));
100
- rb_hash_aset(hash, rb_str_new2("bitness"), rb_str_new2(bitness));
101
- rb_hash_aset(hash, rb_str_new2("type"), rb_str_new2(type));
133
+ VALUE blob = rbhash_get_key(token, "blob", T_STRING);
134
+ VALUE serial = rbhash_get_key(token, "serial", T_STRING);
135
+ VALUE app_name = rbhash_get_key(token, "app_name", T_STRING);
136
+ VALUE flag1 = rbhash_get_key(token, "flags1", T_FIXNUM);
137
+ VALUE flag2 = rbhash_get_key(token, "flags2", T_FIXNUM);
102
138
 
103
- return hash;
139
+ memset(dpdata, 0, sizeof(*dpdata));
140
+
141
+ strcpy(dpdata->Blob, rb_string_value_cstr(&blob));
142
+ strncpy(dpdata->Serial, rb_string_value_cstr(&serial), sizeof(dpdata->Serial));
143
+ strncpy(dpdata->AppName, rb_string_value_cstr(&app_name), sizeof(dpdata->AppName));
144
+ dpdata->DPFlags[0] = rb_fix2int(flag1);
145
+ dpdata->DPFlags[1] = rb_fix2int(flag2);
104
146
  }
105
147
 
106
148
 
149
+
107
150
  /*
108
- * generate a password
109
- * this will not work with all the dpx files available, it must be prepared for it
151
+ * Generate an OTP from the given token, if the token allows it.
110
152
  */
111
153
  static VALUE vacman_generate_password(VALUE module, VALUE token) {
112
154
  TDigipassBlob dpdata;
@@ -116,11 +158,11 @@ static VALUE vacman_generate_password(VALUE module, VALUE token) {
116
158
  aat_ascii password[18];
117
159
  memset(password, 0, sizeof(password));
118
160
 
119
- aat_int32 result = AAL2GenPassword(&dpdata, &KernelParms, password, NULL);
161
+ aat_int32 result = AAL2GenPassword(&dpdata, &g_KernelParms, password, NULL);
120
162
  digipass_to_rbhash(&dpdata, token);
121
163
 
122
164
  if (result != 0) {
123
- vacman_raise_error("AAL2GenPassword", result);
165
+ vacman_library_error("AAL2GenPassword", result);
124
166
  return Qnil;
125
167
  }
126
168
 
@@ -129,7 +171,7 @@ static VALUE vacman_generate_password(VALUE module, VALUE token) {
129
171
 
130
172
 
131
173
  /*
132
- * Properties names and IDs registry
174
+ * Vacman properties names and IDs registry
133
175
  */
134
176
  struct token_property {
135
177
  const char *name;
@@ -192,10 +234,11 @@ static long vacman_get_property_id(char *property_name) {
192
234
  }
193
235
  }
194
236
 
195
- rb_raise(e_vacmanerror, "Invalid property name `%s'", property_name);
237
+ rb_raise(e_VacmanError, "Invalid property name `%s'", property_name);
196
238
  return 0;
197
239
  }
198
240
 
241
+
199
242
  /*
200
243
  * Get token property names
201
244
  */
@@ -212,7 +255,7 @@ static VALUE vacman_get_token_property_names(void) {
212
255
 
213
256
 
214
257
  /*
215
- * Get token properties
258
+ * Get the given property value from the given token.
216
259
  */
217
260
  static VALUE vacman_get_token_property(VALUE module, VALUE token, VALUE property) {
218
261
  TDigipassBlob dpdata;
@@ -220,19 +263,19 @@ static VALUE vacman_get_token_property(VALUE module, VALUE token, VALUE property
220
263
 
221
264
  aat_ascii value[64];
222
265
  aat_int32 property_id = vacman_get_property_id(StringValueCStr(property));
223
- aat_int32 result = AAL2GetTokenProperty(&dpdata, &KernelParms, property_id, value);
266
+ aat_int32 result = AAL2GetTokenProperty(&dpdata, &g_KernelParms, property_id, value);
224
267
 
225
268
  if (result == 0) {
226
269
  return rb_str_new2(value);
227
270
  } else {
228
- vacman_raise_error("AAL2GetTokenProperty", result);
271
+ vacman_library_error("AAL2GetTokenProperty", result);
229
272
  return Qnil;
230
273
  }
231
274
  }
232
275
 
233
276
 
234
277
  /*
235
- * Set token properties
278
+ * Set the given token property to the given value.
236
279
  */
237
280
  static VALUE vacman_set_token_property(VALUE module, VALUE token, VALUE property, VALUE rbval) {
238
281
  TDigipassBlob dpdata;
@@ -242,75 +285,75 @@ static VALUE vacman_set_token_property(VALUE module, VALUE token, VALUE property
242
285
 
243
286
  rbhash_to_digipass(token, &dpdata);
244
287
 
245
- aat_int32 result = AAL2SetTokenProperty(&dpdata, &KernelParms, property_id, value);
288
+ aat_int32 result = AAL2SetTokenProperty(&dpdata, &g_KernelParms, property_id, value);
246
289
 
247
290
  digipass_to_rbhash(&dpdata, token);
248
291
 
249
292
  if (result == 0) {
250
293
  return Qtrue;
251
294
  } else {
252
- vacman_raise_error("AAL2SetTokenProperty", result);
295
+ vacman_library_error("AAL2SetTokenProperty", result);
253
296
  return Qnil;
254
297
  }
255
298
  }
256
299
 
257
300
 
258
301
  /*
259
- * Set token static password
302
+ * Changes the static password on the given token.
260
303
  */
261
304
  static VALUE vacman_set_token_pin(VALUE module, VALUE token, VALUE pin) {
262
305
  TDigipassBlob dpdata;
263
306
 
264
307
  if (!RB_TYPE_P(pin, T_STRING)) {
265
- rb_raise(e_vacmanerror, "invalid pin given, requires a string");
308
+ rb_raise(e_VacmanError, "invalid pin given, requires a string");
266
309
  return Qnil;
267
310
  }
268
311
 
269
312
  rbhash_to_digipass(token, &dpdata);
270
313
 
271
314
  aat_ascii *passwd = StringValueCStr(pin);
272
- aat_int32 result = AAL2ChangeStaticPassword(&dpdata, &KernelParms, passwd, passwd);
315
+ aat_int32 result = AAL2ChangeStaticPassword(&dpdata, &g_KernelParms, passwd, passwd);
273
316
 
274
317
  digipass_to_rbhash(&dpdata, token);
275
318
 
276
319
  if (result == 0) {
277
320
  return Qtrue;
278
321
  } else {
279
- vacman_raise_error("AAL2ChangeStaticPassword", result);
322
+ vacman_library_error("AAL2ChangeStaticPassword", result);
280
323
  return Qnil;
281
324
  }
282
325
  }
283
326
 
284
327
 
285
328
  /*
286
- * verify password
287
- * this is the main usecase, check the use input for authentication
329
+ * Verifies the given OTP against the given token.
288
330
  */
289
- static VALUE vacman_verify_password(VALUE module, VALUE token, VALUE password ) {
331
+ static VALUE vacman_verify_password(VALUE module, VALUE token, VALUE password) {
290
332
  TDigipassBlob dpdata;
291
333
 
292
334
  rbhash_to_digipass(token, &dpdata);
293
335
 
294
- aat_int32 result = AAL2VerifyPassword(&dpdata, &KernelParms, rb_string_value_cstr(&password), 0);
336
+ aat_int32 result = AAL2VerifyPassword(&dpdata, &g_KernelParms, rb_string_value_cstr(&password), 0);
295
337
 
296
338
  digipass_to_rbhash(&dpdata, token);
297
339
 
298
340
  if (result == 0)
299
341
  return Qtrue;
300
342
  else {
301
- vacman_raise_error("AAL2VerifyPassword", result);
343
+ vacman_library_error("AAL2VerifyPassword", result);
302
344
  return Qnil;
303
345
  }
304
346
  }
305
347
 
306
348
 
307
-
308
349
  /*
309
- * Import a .DPX file containing token seeds and initialisation values.
350
+ * Imports a .DPX file containing token seeds and initialisation values.
351
+ *
352
+ * Pass the pre-shared key to validate it as the second argument. The
353
+ * key is not validated by the AAL2 library, if you pass a different
354
+ * key than the one that was used to create the DPX, you will get back
355
+ * tokens that generate different OTPs.
310
356
  *
311
- * Pass the pre-shared key to validate it as the second argument. Or if
312
- * you don't have the key, replace the DC line with one from a file you
313
- * know the key. Yes.
314
357
  */
315
358
  static VALUE vacman_import(VALUE module, VALUE filename, VALUE key) {
316
359
  TDPXHandle dpx_handle;
@@ -318,11 +361,15 @@ static VALUE vacman_import(VALUE module, VALUE filename, VALUE key) {
318
361
  aat_ascii appl_names[13*8];
319
362
  aat_int16 token_count;
320
363
 
321
- aat_int32 result = AAL2DPXInit(&dpx_handle, rb_string_value_cstr(&filename), rb_string_value_cstr(&key),
322
- &appl_count, appl_names, &token_count);
364
+ aat_int32 result = AAL2DPXInit(&dpx_handle,
365
+ rb_string_value_cstr(&filename),
366
+ rb_string_value_cstr(&key),
367
+ &appl_count,
368
+ appl_names,
369
+ &token_count);
323
370
 
324
371
  if (result != 0) {
325
- vacman_raise_error("AAL2DPXInit", result);
372
+ vacman_library_error("AAL2DPXInit", result);
326
373
  return Qnil;
327
374
  }
328
375
 
@@ -335,7 +382,7 @@ static VALUE vacman_import(VALUE module, VALUE filename, VALUE key) {
335
382
 
336
383
  while (1) {
337
384
  result = AAL2DPXGetToken(&dpx_handle,
338
- &KernelParms,
385
+ &g_KernelParms,
339
386
  appl_names,
340
387
  sw_out_serial_No,
341
388
  sw_out_type,
@@ -344,9 +391,10 @@ static VALUE vacman_import(VALUE module, VALUE filename, VALUE key) {
344
391
 
345
392
 
346
393
  if (result < 0) {
347
- vacman_raise_error("AAL2DPXGetToken", result);
394
+ vacman_library_error("AAL2DPXGetToken", result);
348
395
  return Qnil;
349
396
  }
397
+
350
398
  if (result == 107) break;
351
399
 
352
400
  VALUE hash = rb_hash_new();
@@ -361,30 +409,48 @@ static VALUE vacman_import(VALUE module, VALUE filename, VALUE key) {
361
409
  return list;
362
410
  }
363
411
 
412
+
413
+ /*
414
+ * Vacman Controller kernel properties
415
+ */
364
416
  struct kernel_property {
365
417
  const char *name;
366
418
  aat_int32 *value;
367
419
  aat_int32 deflt;
368
420
  };
369
421
  static struct kernel_property kernel_properties[] = {
370
- { "ITimeWindow", &KernelParms.ITimeWindow, 30 }, // Identification Window size in time steps
371
- { "STimeWindow", &KernelParms.STimeWindow, 24 }, // Signature Window size in secs
372
- { "DiagLevel", &KernelParms.DiagLevel, 0 }, // Requested Diagnostic Level
373
- { "GMTAdjust", &KernelParms.GMTAdjust, 0 }, // GMT Time adjustment to perform
374
- { "CheckChallenge", &KernelParms.CheckChallenge, 0 }, // Verify Challenge Corrupted (mandatory for Gordian)
375
- { "IThreshold", &KernelParms.IThreshold, 3 }, // Identification Error Threshold
376
- { "SThreshold", &KernelParms.SThreshold, 1 }, // Signature Error Threshold
377
- { "ChkInactDays", &KernelParms.ChkInactDays, 0 }, // Check Inactive Days
378
- { "DeriveVector", &KernelParms.DeriveVector, 0 }, // Vector used to make Data Encryption unique
379
- { "SyncWindow", &KernelParms.SyncWindow, 2 }, // Synchronisation Time Window (h)
380
- { "OnLineSG", &KernelParms.OnLineSG, 2 }, // On line signature
381
- { "EventWindow", &KernelParms.EventWindow, 100 }, // Event Window size in nbr of iterations
382
- { "HSMSlotId", &KernelParms.HSMSlotId, 0 }, // HSM Slot id uses to store DB and Transport Key
422
+ { "ITimeWindow", &g_KernelParms.ITimeWindow, 30 }, // Identification Window size in time steps
423
+ { "STimeWindow", &g_KernelParms.STimeWindow, 24 }, // Signature Window size in secs
424
+ { "DiagLevel", &g_KernelParms.DiagLevel, 0 }, // Requested Diagnostic Level
425
+ { "GMTAdjust", &g_KernelParms.GMTAdjust, 0 }, // GMT Time adjustment to perform
426
+ { "CheckChallenge", &g_KernelParms.CheckChallenge, 0 }, // Verify Challenge Corrupted (mandatory for Gordian)
427
+ { "IThreshold", &g_KernelParms.IThreshold, 3 }, // Identification Error Threshold
428
+ { "SThreshold", &g_KernelParms.SThreshold, 1 }, // Signature Error Threshold
429
+ { "ChkInactDays", &g_KernelParms.ChkInactDays, 0 }, // Check Inactive Days
430
+ { "DeriveVector", &g_KernelParms.DeriveVector, 0 }, // Vector used to make Data Encryption unique
431
+ { "SyncWindow", &g_KernelParms.SyncWindow, 2 }, // Synchronisation Time Window (h)
432
+ { "OnLineSG", &g_KernelParms.OnLineSG, 2 }, // On line signature
433
+ { "EventWindow", &g_KernelParms.EventWindow, 100 }, // Event Window size in nbr of iterations
434
+ { "HSMSlotId", &g_KernelParms.HSMSlotId, 0 }, // HSM Slot id uses to store DB and Transport Key
383
435
  };
384
436
  static size_t kernel_properties_count = sizeof(kernel_properties)/sizeof(struct kernel_property);
385
437
 
386
438
  /*
387
- * Get kernel property names
439
+ * Initialise the kernel parameters with their defaults
440
+ */
441
+ static void vacman_init_kernel_params() {
442
+ memset(&g_KernelParms, 0, sizeof(g_KernelParms));
443
+
444
+ g_KernelParms.ParmCount = 19; /* Number of valid parameters in this list */
445
+
446
+ for (size_t i = 0; i < kernel_properties_count; i++) {
447
+ *kernel_properties[i].value = kernel_properties[i].deflt;
448
+ }
449
+ }
450
+
451
+
452
+ /*
453
+ * Get kernel parameter names
388
454
  */
389
455
  static VALUE vacman_get_kernel_property_names(void) {
390
456
  VALUE ret = rb_ary_new();
@@ -397,6 +463,7 @@ static VALUE vacman_get_kernel_property_names(void) {
397
463
  return ret;
398
464
  }
399
465
 
466
+
400
467
  /*
401
468
  * Set kernel parameter
402
469
  */
@@ -411,7 +478,7 @@ static VALUE vacman_set_kernel_param(VALUE module, VALUE paramname, VALUE rbval)
411
478
  }
412
479
  }
413
480
 
414
- rb_raise(e_vacmanerror, "Invalid kernel param %s", name);
481
+ rb_raise(e_VacmanError, "Invalid kernel param %s", name);
415
482
  return Qnil;
416
483
  }
417
484
 
@@ -428,48 +495,36 @@ static VALUE vacman_get_kernel_param(VALUE module, VALUE paramname) {
428
495
  }
429
496
  }
430
497
 
431
- rb_raise(e_vacmanerror, "Invalid kernel param %s", name);
498
+ rb_raise(e_VacmanError, "Invalid kernel param %s", name);
432
499
  return Qnil;
433
500
  }
434
501
 
435
- /*
436
- * Init the kernel parameters, with their defaults
437
- */
438
- static void init_kernel_params() {
439
- memset(&KernelParms, 0, sizeof(TKernelParms));
440
-
441
- KernelParms.ParmCount = 19; /* Number of valid parameters in this list */
442
-
443
- for (size_t i = 0; i < kernel_properties_count; i++) {
444
- *kernel_properties[i].value = kernel_properties[i].deflt;
445
- }
446
- }
447
-
448
502
 
449
503
  /*
450
- * rubys entry point to load the extension
504
+ * Extension entry point
451
505
  */
452
- void Init_vacman_controller(void) {
453
- VALUE vacman_module = rb_define_module("VacmanLowLevel");
454
-
455
- e_vacmanerror = rb_define_class("VacmanError", rb_eStandardError);
456
- init_kernel_params();
457
-
458
- rb_define_singleton_method(vacman_module, "version", vacman_library_version, 0);
459
-
460
- rb_define_singleton_method(vacman_module, "import", vacman_import, 2);
461
-
462
- rb_define_singleton_method(vacman_module, "generate_password", vacman_generate_password, 1);
463
- rb_define_singleton_method(vacman_module, "verify_password", vacman_verify_password, 2);
464
-
465
- rb_define_singleton_method(vacman_module, "get_kernel_param", vacman_get_kernel_param, 1);
466
- rb_define_singleton_method(vacman_module, "set_kernel_param", vacman_set_kernel_param, 2);
467
-
468
- rb_define_singleton_method(vacman_module, "get_token_property", vacman_get_token_property, 2);
469
- rb_define_singleton_method(vacman_module, "set_token_property", vacman_set_token_property, 3);
470
-
471
- rb_define_singleton_method(vacman_module, "set_token_pin", vacman_set_token_pin, 2);
472
-
473
- rb_define_singleton_method(vacman_module, "token_property_names", vacman_get_token_property_names, 0);
474
- rb_define_singleton_method(vacman_module, "kernel_property_names", vacman_get_kernel_property_names, 0);
506
+ void Init_low_level(void) {
507
+ VALUE controller = rb_define_module("VacmanController");
508
+ VALUE lowlevel = rb_define_module_under(controller, "LowLevel");
509
+
510
+ e_VacmanError = rb_define_class_under(controller, "Error", rb_eStandardError);
511
+
512
+ vacman_init_kernel_params();
513
+
514
+ /* Global methods */
515
+ rb_define_singleton_method(lowlevel, "library_version", vacman_library_version, 0);
516
+ rb_define_singleton_method(lowlevel, "import", vacman_import, 2);
517
+
518
+ /* Token methods */
519
+ rb_define_singleton_method(lowlevel, "token_property_names", vacman_get_token_property_names, 0);
520
+ rb_define_singleton_method(lowlevel, "get_token_property", vacman_get_token_property, 2);
521
+ rb_define_singleton_method(lowlevel, "set_token_property", vacman_set_token_property, 3);
522
+ rb_define_singleton_method(lowlevel, "generate_password", vacman_generate_password, 1);
523
+ rb_define_singleton_method(lowlevel, "verify_password", vacman_verify_password, 2);
524
+ rb_define_singleton_method(lowlevel, "set_token_pin", vacman_set_token_pin, 2);
525
+
526
+ /* Kernel methods */
527
+ rb_define_singleton_method(lowlevel, "kernel_property_names", vacman_get_kernel_property_names, 0);
528
+ rb_define_singleton_method(lowlevel, "get_kernel_param", vacman_get_kernel_param, 1);
529
+ rb_define_singleton_method(lowlevel, "set_kernel_param", vacman_set_kernel_param, 2);
475
530
  }
@@ -1,176 +1,60 @@
1
- require 'vacman_controller/vacman_controller'
1
+ require 'vacman_controller/low_level'
2
+ require 'vacman_controller/token'
3
+ require 'vacman_controller/kernel'
4
+ require 'vacman_controller/error'
2
5
 
3
- # Provides VACMAN Controller functionality to identify and authorize user via VASCO DIGIPASS tokens.
4
- #
6
+ # Wraps VACMAN Controller functionality for Ruby.
5
7
  #
6
8
  module VacmanController
7
- extend self
8
-
9
- # Import .dpx file containing the secure token-data
10
- #
11
- # == Parameters:
12
- # filename::
13
- # The path of the .dpx file to load
14
- # key::
15
- # The secure key to decrypt the dpx file
16
- #
17
- # == Returns:
18
- # A list of hashes. Each hash contains
19
- # serial: the serial number of the token
20
- # blob: the blob containing some secret magic data
21
- # app_name: the application name (the security method)
22
- # flags1: some flags
23
- # flags2: more flags
24
- #
25
- # this hash must be persisted and regained for each call of verify_password and generate_password
26
- #
27
- def import(filename, key)
28
- VacmanLowLevel.import(filename, key)
29
- end
30
-
31
-
32
-
33
- # Generate a Password for a user. This does the same as hitting the button on your hardware token
34
- #
35
- # == Parameters:
36
- # hash::
37
- # The hash for a specific token (you get these in import)
38
- #
39
- # == Returns:
40
- # The password string. The password is only valid for a period (todo: add method to change the period, currently its 30 seconds)
41
- #
42
- def generate_password(hash)
43
- VacmanLowLevel.generate_password(hash)
44
- end
45
-
46
-
47
-
48
- # Verify a password. This is the usecase a user sends you a password generated by his token and we have to verify it.
49
- #
50
- # == Parameters:
51
- # hash::
52
- # The hash for a specific token (you get these in import)
53
- # pw::
54
- # The password provided by the user
55
- #
56
- # == Returns:
57
- # true if the password is valid, false otherwise
58
- #
59
- # ATTENTION: it is very important to persist the hash afterwards!!!
60
- #
61
- def verify_password(hash, pw)
62
- VacmanLowLevel.verify_password(hash, pw)
63
- end
64
-
65
-
66
-
67
- # Gets the available kernel property names
68
- #
69
- def kernel_property_names
70
- @_kernel_property_names ||= VacmanLowLevel.kernel_property_names
71
- end
72
-
73
-
74
-
75
- # Get a kernel parameter, wich is a basically a setting for vacman controller
76
- #
77
- # == Parameters:
78
- # name::
79
- # the param name. Most TKernelParms struct elements are accessible.
80
- #
81
- def get_kernel_param(name)
82
- VacmanLowLevel.get_kernel_param(name)
83
- end
84
-
85
-
86
-
87
- # Change a kernel parameter, wich is a basically a setting for vacman controller
88
- #
89
- # == Parameters:
90
- # name::
91
- # the param name. Most TKernelParms struct elements are accessible.
92
- # val::
93
- # the fixnum value
94
- #
95
- def set_kernel_param(name, val)
96
- VacmanLowLevel.set_kernel_param(name, val)
97
- end
98
9
 
99
-
100
-
101
- # Returns all configured kernel parameters
102
- #
103
- def get_kernel_all_parameters
104
- kernel_property_names.inject({}) do |h, name|
105
- h.update(name => (get_kernel_param(name) rescue "ERROR: #$!"))
10
+ VERSION = '0.5.0'
11
+
12
+ class << self
13
+ # Imports a .dpx file containing the token key material.
14
+ #
15
+ # == Parameters:
16
+ #
17
+ # filename::
18
+ # The path of the .dpx file to load
19
+ #
20
+ # key::
21
+ # The transport key to decrypt the dpx file
22
+ #
23
+ # == Returns:
24
+ # An Array of Ruby Hashes. Each Hash contains the following keys:
25
+ #
26
+ # serial: the serial number of the token
27
+ # blob: the blob containing some secret magic data
28
+ # app_name: the application name (the security method)
29
+ # flags1: flags
30
+ # flags2: flags
31
+ #
32
+ # This is only for low-level usage. For a Ruby API, look at
33
+ # +VacmanController::Token.import+.
34
+ #
35
+ def import(filename, key)
36
+ VacmanController::LowLevel.import(filename, key)
37
+
38
+ rescue VacmanController::Error => e
39
+ # We handle two undocumented error codes here
40
+ case e.error_code
41
+ when -15
42
+ raise VacmanController::Error, "#{e.library_method} error #{e.error_code}: invalid transport key"
43
+
44
+ when -20
45
+ raise VacmanController::Error, "#{e.library_method} error #{e.error_code}: cannot open DPX file"
46
+
47
+ else
48
+ raise # Sorry, I did my best.
49
+
50
+ end
106
51
  end
107
- end
108
-
109
-
110
-
111
- # Gets the available token property names
112
- #
113
- def token_property_names
114
- @_token_property_names ||= VacmanLowLevel.token_property_names
115
- end
116
-
117
-
118
-
119
- # Get a token single property
120
- #
121
- # == Parameters:
122
- # hash::
123
- # the hash for a specific token (you get these in import)
124
- # property::
125
- # the property name. See +token_property_names+
126
- #
127
- def get_token_property(hash, property)
128
- VacmanLowLevel.get_token_property(hash, property)
129
- end
130
52
 
131
-
132
-
133
- # Set a token single property
134
- #
135
- # == Parameters:
136
- # hash::
137
- # the hash for a specific token (you get these in import)
138
- # property::
139
- # the property name. See +token_property_names+
140
- # value::
141
- # the property value. Only values convertible to integer are supported.
142
- #
143
- # possible names:
144
- #
145
- #
146
- def set_token_property(hash, property, value)
147
- VacmanLowLevel.set_token_property(hash, property, value)
148
- end
149
-
150
-
151
-
152
- # Set a token PIN
153
- #
154
- # == Parameters:
155
- # hash::
156
- # the hash for a specific token (you get these in import)
157
- # pin::
158
- # the new PIN. must be a string.
159
- #
160
- # possible names:
161
- #
162
- #
163
- def set_token_pin(hash, pin)
164
- VacmanLowLevel.set_token_pin(hash, pin)
165
- end
166
-
167
-
168
-
169
- # Returns all properties configured for a token
170
- #
171
- def get_token_all_properties(hash)
172
- token_property_names.inject({}) do |h, name|
173
- h.update(name => (get_token_property(hash, name) rescue "ERROR: #$!"))
53
+ # Returns the +Kernel+ module
54
+ #
55
+ def kernel
56
+ VacmanController::Kernel
174
57
  end
175
58
  end
59
+
176
60
  end
@@ -0,0 +1,16 @@
1
+ module VacmanController
2
+
3
+ # Represents a Vacman Controller Library error.
4
+ #
5
+ class Error < StandardError
6
+ # The AAL2 library method that errored
7
+ attr_reader :library_method
8
+
9
+ # The error code returned by the AAL2 library
10
+ attr_reader :error_code
11
+
12
+ # The error message retrieved by the AAL2 library
13
+ attr_reader :error_message
14
+ end
15
+
16
+ end
@@ -0,0 +1,71 @@
1
+ module VacmanController
2
+
3
+ module Kernel
4
+ class << self
5
+ # Returns the library version as an hash
6
+ #
7
+ def version
8
+ @_version = VacmanController::LowLevel.library_version
9
+ end
10
+
11
+
12
+ # Gets the available kernel property names
13
+ #
14
+ def property_names
15
+ @_property_names ||= VacmanController::LowLevel.kernel_property_names.freeze
16
+ end
17
+
18
+
19
+ # Shows the kernel version, bitness, type and parameters in your
20
+ # development console.
21
+ #
22
+ def inspect
23
+ "#<#{self.name} version=#{version['version'].inspect} bitness=#{version['bitness'].inspect} "\
24
+ "type=#{version['type'].inspect} parameters=#{all.inspect}>>"
25
+ end
26
+
27
+
28
+ # Returns all configured parameters
29
+ #
30
+ def all
31
+ property_names.inject({}) do |h, name|
32
+ h.update(name => (self[name] rescue "ERROR: #$!"))
33
+ end
34
+ end
35
+ alias to_h all
36
+
37
+
38
+ # Get a Kernel property, that is a runtime parameter of Vacman Controller,
39
+ # stored in the TKernelParms structure.
40
+ #
41
+ # == Parameters:
42
+ # name::
43
+ # The param name. See +property_names+ for a list of available property
44
+ # names.
45
+ #
46
+ def [](name)
47
+ VacmanController::LowLevel.get_kernel_param(name)
48
+ end
49
+
50
+
51
+ # Set a Kernel property.
52
+ #
53
+ # == Parameters:
54
+ # name::
55
+ # the param name. See +property_names+ for a list of available property
56
+ # names. The Kernel parameters are all int32 properties.
57
+ #
58
+ # val::
59
+ # the integer value
60
+ #
61
+ def []=(name, val)
62
+ Mutex.synchronize do
63
+ VacmanController::LowLevel.set_kernel_param(name, val)
64
+ end
65
+ end
66
+
67
+ Mutex = Thread::Mutex.new
68
+ end
69
+ end
70
+
71
+ end
@@ -0,0 +1,182 @@
1
+ require 'vacman_controller/token/properties'
2
+
3
+ module VacmanController
4
+
5
+ class Token
6
+ # Opens the given dpx_filename with the given transport key and,
7
+ # if successful, returns Token instances for all tokens in the
8
+ # DPX file.
9
+ #
10
+ def self.import(dpx_filename, transport_key)
11
+ VacmanController.import(dpx_filename, transport_key).map do |hash|
12
+ Token.new(hash)
13
+ end
14
+ end
15
+
16
+
17
+ # Initialises a Token instance with the given token hash.
18
+ #
19
+ def initialize(token_hash)
20
+ @token_hash = token_hash
21
+ end
22
+
23
+
24
+ # Return the token serial number
25
+ #
26
+ def serial
27
+ @token_hash.fetch('serial').dup
28
+ end
29
+
30
+
31
+ # Returns the token Application Name
32
+ #
33
+ def app_name
34
+ @token_hash.fetch('app_name').dup
35
+ end
36
+
37
+
38
+ # Renders this token in your development console
39
+ # and in your logs (possibly)
40
+ #
41
+ def inspect
42
+ "#<#{self.class.name} serial=#{serial.inspect} app_name=#{app_name.inspect}>"
43
+ end
44
+
45
+
46
+ # Returns the token as an hash, that is suitable for passing to
47
+ # the low-level functions, or for persistance purposes.
48
+ #
49
+ def to_h
50
+ @token_hash
51
+ end
52
+
53
+
54
+ # Verify a password. This is the usecase a user sends you an OTP
55
+ # generated by their token and we have to verify it.
56
+ #
57
+ # == Parameters:
58
+ # otp::
59
+ # The OTP provided by the user
60
+ #
61
+ # == Returns:
62
+ # true if the password is valid, false otherwise
63
+ #
64
+ # ATTENTION: it is very important to persist the token hash
65
+ # afterwards.
66
+ #
67
+ def verify(otp)
68
+ verify!(otp)
69
+ rescue VacmanController::Error
70
+ false
71
+ end
72
+
73
+
74
+ # Same as verify, but raises a VacmanController::Error if OTP verification
75
+ # fails.
76
+ #
77
+ def verify!(otp)
78
+ VacmanController::LowLevel.verify_password(@token_hash, otp.to_s)
79
+ end
80
+
81
+
82
+ # Generate an OTPfrom this token. This does the same as hitting the button
83
+ # on the hardware token.
84
+ #
85
+ # == Returns:
86
+ # The OTP as a String. The OTP is only valid for a limited time period.
87
+ #
88
+ # Not all tokens support OTP generation.
89
+ #
90
+ def generate
91
+ VacmanController::LowLevel.generate_password(@token_hash)
92
+ end
93
+
94
+
95
+ # Set this token's PIN
96
+ #
97
+ # == Parameters:
98
+ # pin::
99
+ # the new PIN. Must be coercible to String.
100
+ #
101
+ def set_pin(pin)
102
+ VacmanController::LowLevel.set_token_pin(@token_hash, pin.to_s)
103
+ end
104
+
105
+
106
+ ####################################################################
107
+ ##### Properties Management
108
+ ####################################################################
109
+
110
+ # Enables the PIN on this token
111
+ #
112
+ def enable_pin!
113
+ properties[:pin_enabled] = 1
114
+ true
115
+ end
116
+
117
+
118
+ # Disables the PIN on this token
119
+ #
120
+ def disable_pin!
121
+ properties[:pin_enabled] = 2
122
+ true
123
+ end
124
+
125
+
126
+ # Forces PIN change on this token
127
+ #
128
+ def force_pin_change!
129
+ properties[:pin_change_forced] = 1
130
+ true
131
+ end
132
+
133
+
134
+ # Resets the token error count
135
+ #
136
+ def reset_error_count!
137
+ properties[:error_count] = 0
138
+ true
139
+ end
140
+
141
+
142
+ # Sets the "disabled" token status
143
+ #
144
+ def disable!
145
+ properties[:token_status] = 0
146
+ true
147
+ end
148
+
149
+
150
+ # Set the primary application enabled status
151
+ #
152
+ def enable_primary_only!
153
+ properties[:token_status] = 1
154
+ true
155
+ end
156
+
157
+
158
+ # Set the backup application enabled status
159
+ #
160
+ def enable_backup_only!
161
+ properties[:token_status] = 2
162
+ true
163
+ end
164
+
165
+
166
+ # Set both primary and backup application enabled status
167
+ #
168
+ def enable!
169
+ properties[:token_status] = 3
170
+ true
171
+ end
172
+
173
+
174
+ # Returns a +Token::Properties+ object giving low-level access to the
175
+ # token properties.
176
+ #
177
+ def properties
178
+ @_properties = VacmanController::Token::Properties.new(self)
179
+ end
180
+ end
181
+
182
+ end
@@ -0,0 +1,193 @@
1
+ module VacmanController
2
+ class Token
3
+
4
+ class Properties
5
+ class << self
6
+ # Gets the available token property names
7
+ #
8
+ def names
9
+ @_names ||= VacmanController::LowLevel.token_property_names.freeze
10
+ end
11
+ end
12
+
13
+
14
+ def initialize(token)
15
+ @token = token
16
+ end
17
+
18
+
19
+ def inspect
20
+ all.inspect
21
+ end
22
+
23
+
24
+ def all
25
+ self.class.names.inject({}) do |h, name|
26
+ h.update(name => (self[name] rescue "ERROR: #$!"))
27
+ end
28
+ end
29
+ alias to_h all
30
+
31
+
32
+ # Get a Token property
33
+ #
34
+ # == Parameters:
35
+ #
36
+ # property::
37
+ # the property name. See +Token::Properties.names+
38
+ #
39
+ def [](name)
40
+ name = name.to_s
41
+ value = VacmanController::LowLevel.get_token_property(@token.to_h, name)
42
+
43
+ cast(name, value)
44
+ end
45
+
46
+
47
+ # Set a Token property
48
+ #
49
+ # == Parameters:
50
+ #
51
+ # property::
52
+ # the property name. See +Token.property_names+
53
+ #
54
+ # value::
55
+ # the property value. Only values convertible to integer are
56
+ # supported.
57
+ #
58
+ def []=(name, value)
59
+ name = name.to_s
60
+ value = value.to_i
61
+
62
+ check_bounded_property!(name, value)
63
+
64
+ VacmanController::LowLevel.set_token_property(@token.to_h, name, value)
65
+ end
66
+
67
+
68
+ protected
69
+ def bounded_property?(name)
70
+ PROPERTY_BOUNDS.key?(name)
71
+ end
72
+
73
+ # The library also does these checks, but we want to present
74
+ # custom error message to the caller.
75
+ #
76
+ def check_bounded_property!(name, value)
77
+ return unless bounded_property?(name)
78
+
79
+ min, max = PROPERTY_BOUNDS.fetch(name)
80
+
81
+ if value < min || value > max
82
+ raise VacmanController::Error,
83
+ "Invalid #{name} value provided: #{value}. " \
84
+ "Must be between greater than #{min} and less than #{max}."
85
+ end
86
+
87
+ true
88
+ end
89
+
90
+ PROPERTY_BOUNDS = {
91
+ 'last_time_used' => [ 631152000, 2147483647 ],
92
+
93
+ 'last_time_shift' => [ -100_000, 100_000 ],
94
+
95
+ 'pin_min_length' => [ 3, 8 ],
96
+ 'pin_minimum_length' => [ 3, 8 ],
97
+
98
+ 'virtual_token_grace_period' => [ 1, 364 ],
99
+
100
+ 'virtual_token_remain_use' => [ 0, 254 ],
101
+
102
+ 'event_value' => [ 0, 4_294_967_294 ],
103
+ }
104
+
105
+ def cast(property, value)
106
+
107
+ # Short-circuit on 'NA'
108
+ return nil if value == 'NA' or value == 'DISABLE'
109
+
110
+ case property
111
+ when # Integer values
112
+ 'use_count',
113
+ 'pin_len',
114
+ 'pin_length',
115
+ 'pin_min_len',
116
+ 'pin_minimum_length',
117
+ 'last_time_shift',
118
+ 'virtual_token_remain_use',
119
+ 'error_count',
120
+ 'event_value',
121
+ 'last_event_value',
122
+ 'max_dtf_number',
123
+ 'response_len',
124
+ 'response_length',
125
+ 'time_step'
126
+
127
+ value.to_i
128
+
129
+ when # Boolean values
130
+ 'time_based_algo',
131
+ 'event_based_algo',
132
+ 'pin_supported',
133
+ 'unlock_supported',
134
+ 'pin_ch_on',
135
+ 'pin_change_enabled',
136
+ 'pin_enabled',
137
+ 'pin_ch_forced',
138
+ 'pin_change_forced',
139
+ 'sync_windows',
140
+ 'primary_token_enabled',
141
+ 'virtual_token_supported',
142
+ 'virtual_token_enabled',
143
+ 'derivation_supported',
144
+ 'response_chk',
145
+ 'response_checksum',
146
+ 'triple_des_used',
147
+ 'use_3des'
148
+
149
+ case value
150
+ when 'YES' then true
151
+ when 'NO' then false
152
+ end
153
+
154
+ when # Date/time values
155
+ 'last_time_used',
156
+ 'virtual_token_grace_period'
157
+
158
+ # AAL2 returns UTC values, we add the timezone.
159
+ Time.strptime("#{value} UTC", '%a %b %d %H:%M:%S %Y %Z')
160
+
161
+ when
162
+ 'auth_mode'
163
+
164
+ case value
165
+ when 'RO' then :response_only
166
+ when 'SG' then :signature_application
167
+ when 'CR' then :challenge_response
168
+ when 'MM' then :multi_mode
169
+ when 'UL' then :unlock_v2
170
+ else
171
+ value
172
+ end
173
+
174
+ else # String values
175
+
176
+ value
177
+ end
178
+ end
179
+
180
+ private
181
+ def method_missing(name, *args, &block)
182
+ prop, setter = name.to_s.match(/\A(.+?)(=)?\Z/).values_at(1, 2)
183
+
184
+ if setter
185
+ self[prop] = args.first
186
+ else
187
+ self[prop]
188
+ end
189
+ end
190
+ end
191
+
192
+ end
193
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vacman_controller
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcus Lankenau
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-01-07 00:00:00.000000000 Z
12
+ date: 2019-04-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake-compiler
@@ -25,7 +25,36 @@ dependencies:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0'
28
- description: Authenticate user via vacman controller
28
+ - !ruby/object:Gem::Dependency
29
+ name: rspec
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: guard-rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ description: Expose the AAL2 SDK API via a set of Ruby classes optimised for developer
57
+ happiness
29
58
  email:
30
59
  - marcus.lankenau@gmail.com
31
60
  - marcello.barnaba@gmail.com
@@ -35,9 +64,13 @@ extensions:
35
64
  extra_rdoc_files: []
36
65
  files:
37
66
  - ext/vacman_controller/extconf.rb
38
- - ext/vacman_controller/vacman_controller.c
67
+ - ext/vacman_controller/low_level.c
39
68
  - lib/vacman_controller.rb
40
- homepage: http://github.com/ifad/vacman_controller
69
+ - lib/vacman_controller/error.rb
70
+ - lib/vacman_controller/kernel.rb
71
+ - lib/vacman_controller/token.rb
72
+ - lib/vacman_controller/token/properties.rb
73
+ homepage: https://github.com/ifad/vacman_controller
41
74
  licenses: []
42
75
  metadata: {}
43
76
  post_install_message:
@@ -56,8 +89,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
56
89
  version: '0'
57
90
  requirements: []
58
91
  rubyforge_project:
59
- rubygems_version: 2.5.2.1
92
+ rubygems_version: 2.7.6
60
93
  signing_key:
61
94
  specification_version: 4
62
- summary: Access to the vacman controller library
95
+ summary: Ruby layer to access VASCO Vacman Controller functions
63
96
  test_files: []