ephemeral_calc 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d8cecf935ff387d53df0c4f3a5ab898810061627
4
+ data.tar.gz: 4a303fa845749f4c4f33c7df5e0616fd08e3d018
5
+ SHA512:
6
+ metadata.gz: 134e6ceb11fa9daeafb21b228e9a97289ed25eaa953a525a81d9058a0bf0d5a38f531ff5aedd578933018ebbba0ee0f1c5edcab4812340fc91a8764c3eb06c85
7
+ data.tar.gz: c03aaa19d4f06effd6fe854cd22d4ba7be0f75612a07f4ca256f90776f8209370017da3b1698e609f856929220a0dfeee3b519fa1ed88b7e154cdb177b233aa4
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ /spec/examples.txt
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.2
4
+ before_install: gem install bundler -v 1.10.6
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in eid_utils.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # EphemeralCalc
2
+
3
+ A Ruby gem that allows you to calculate ephemeral identifiers for Eddystone-EID beacons.
4
+
5
+ # Example Usage
6
+
7
+ ```ruby
8
+ # insert real resolver key here
9
+ resolver_public_key = "61136adab1bf302f1c49e860196aeefd8fbaa41518b4c226372d6cc469c47278"
10
+ # generate a new key pair for the beacon
11
+ beacon_keys = EphemeralCalc::KeyPair.new
12
+ # calculate the identity key
13
+ identity_key = beacon_keys.identity_key(resolver_public_key: resolver_public_key)
14
+ # set up the encryptor
15
+ rotation_exponent = 10
16
+ encryptor = EphemeralCalc::Encryptor.new identity_key, rotation_exponent
17
+ # get the initial eid
18
+ initial_eid = encryptor.get_identifier(0)
19
+
20
+ # yield eid values as it rotates
21
+ encryptor.each_identifier do |eid|
22
+ puts "Quantum: #{encryptor.quantum}, EID: #{eid}"
23
+ end
24
+ ```
25
+
26
+ # Command Line Usage
27
+ The `ephemeral_calc` executable is included to allow you to generate keypairs, and do general eid calculation
28
+ without having to write any code.
29
+
30
+ ```shell
31
+ # display CLI help
32
+ ephemeral_calc
33
+
34
+ # set up EphemeralCalc for Google OAuth
35
+ export GOOGLE_CLIENT_ID="xxxx"
36
+ export GOOGLE_CLIENT_SECRET="yyyy"
37
+
38
+ # get EID registration parameters from Google's API using OAuth
39
+ ephemeral_calc eidparams
40
+
41
+ # resolve an EID using a Google project's API key
42
+ API_KEY=xxxx ephemeral_calc resolve 0123456789ABCDEF
43
+
44
+ # resolve EID using OAuth
45
+ ephemeral_calc resolve 0123456789ABCDEF
46
+
47
+ # list first 5 EIDs given identity key, rotation scaler
48
+ ephemeral_calc list 553C66DA1485E9F78849DE00F2CB178E 12 0 5
49
+ ```
50
+
51
+ ## Development
52
+
53
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
54
+
55
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
56
+
57
+ ## Contributing
58
+
59
+ Bug reports and pull requests are welcome on GitHub at https://github.com/radiusnetworks/ephemeral_calc. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
60
+
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require "rake/extensiontask"
4
+
5
+ Rake::ExtensionTask.new "curve25519" do |ext|
6
+ ext.lib_dir = "lib/ephemeral_calc"
7
+ end
8
+
9
+ RSpec::Core::RakeTask.new(:spec)
10
+
11
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "eid_utils"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/rspec ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rspec' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rspec-core', 'rspec')
data/bin/setup ADDED
@@ -0,0 +1,12 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ echo
6
+ echo "== Installing dependencies =="
7
+ bundle install
8
+
9
+ # Do any other automated setup that you need to do here
10
+ echo
11
+ echo "== Compiling Native Extensions =="
12
+ bundle exec rake compile
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ephemeral_calc/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ephemeral_calc"
8
+ spec.version = EphemeralCalc::VERSION
9
+
10
+ spec.authors = ["Radius Networks"]
11
+ spec.email = ["support@radiusnetworks.com"]
12
+
13
+ spec.summary = %q{Tools to calculate Eddystone ephemeral identifiers}
14
+ spec.description = %q{Tools to calculate Eddystone ephemeral identifiers}
15
+ spec.homepage = "https://github.com/RadiusNetworks/ephemeral_calc"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.extensions = %w[ext/curve25519/extconf.rb]
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.10"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "webmock"
27
+ spec.add_development_dependency "rake-compiler"
28
+ end
@@ -0,0 +1,227 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ require 'ephemeral_calc'
5
+
6
+ class App
7
+
8
+ def help
9
+ help_text = <<eos
10
+ Usage:
11
+ ephemeral_calc <command> <arguments>
12
+
13
+ Commands:
14
+
15
+ beacon:
16
+ ephemeral_calc beacon <ik> <scaler> <beacon_initial_time_seconds> <service_initial_time_seconds>
17
+
18
+ Given the identity key, the beacon rotation exponent, and the times of
19
+ registration for the beacon and the service, this computes the eid that the
20
+ beacon is currently broadcasting.
21
+
22
+ track:
23
+ ephemeral_calc track <ik> <scaler> <beacon_initial_time_seconds> <service_initial_time_seconds>
24
+
25
+ Given the identity key, the beacon rotation exponent, and the times of
26
+ registration for the beacon and the service, this displays the current eid and
27
+ outputs new eids as they are calculated, until the user presses <ctrl-c>.
28
+
29
+ eid:
30
+ ephemeral_calc eid <identity_key_hex> <rotation_scaler> <beacon_time_seconds>
31
+
32
+ Generates an EID from the given 16-bytes identity key, the scaler and the
33
+ beacon time in seconds.
34
+
35
+ list:
36
+ ephemeral_calc list <identity_key_hex> <rotation_scaler> <beacon_time_seconds> <count>
37
+
38
+ Lists <count> EIDs, starting at <beacon_time_seconds>
39
+
40
+ resolve:
41
+ ephemeral_calc resolve <eid_hex>
42
+
43
+ Resolves the given EID to a beacon contained in Google's Proximity Beacon API. If you supply an
44
+ api key (via the environment variable "GOOGLE_API_KEY") it will use that and call the
45
+ "getforobserved" API endpoint. Otherwise it will attempt to use OAuth for authentication and
46
+ use the admin api endpoint to get the beacon details.
47
+
48
+ eidparams:
49
+ ephemeral_calc eidparams
50
+
51
+ Gets the EID registration parameters from Google's Proximity Beacon API. Uses environment
52
+ variables "GOOGLE_CLIENT_ID" and "GOOGLE_CLIENT_SECRET" to do the necessary OAuth in order to
53
+ access the API.
54
+
55
+ register:
56
+ ephemeral_calc register <beacon_public_key> <rotation_scaler> <initial_eid> <initial_clock> <namespace> <instance>
57
+
58
+ Registers an EID beacon with Google's Proximity Beacon API. All keys and byte strings should be in hex.
59
+ Uses environment variables "GOOGLE_CLIENT_ID" and "GOOGLE_CLIENT_SECRET" to do the necessary OAuth in
60
+ order to access the API.
61
+
62
+ keygen:
63
+ ephemeral_calc keygen
64
+
65
+ Generates a curve25519 keypair
66
+ eos
67
+ puts help_text
68
+ end
69
+
70
+ COMMANDS = [:beacon, :track, :eid, :list, :resolve, :keygen, :eidparams, :register]
71
+
72
+ def beacon(track = false)
73
+ identity_key = ARGV.shift
74
+ rotation_scalar = ARGV.shift.to_i
75
+ beacon_initial_time = ARGV.shift.to_i
76
+ service_initial_time = ARGV.shift.to_i
77
+ beacon_time_zero = Time.at( service_initial_time - beacon_initial_time)
78
+ encryptor = EphemeralCalc::Encryptor.new identity_key, rotation_scalar, beacon_time_zero
79
+ beacon_time = encryptor.beacon_time
80
+ current_eid = encryptor.get_identifier
81
+ previous_eid = encryptor.get_identifier(beacon_time - 2**rotation_scalar)
82
+ next_eid = encryptor.get_identifier(beacon_time + 2**rotation_scalar)
83
+
84
+ if !track
85
+ puts "Previous EID: #{previous_eid}" if previous_eid
86
+ puts " Current EID: #{current_eid}"
87
+ puts " Next EID: #{next_eid}"
88
+ else
89
+ puts "Press <ctrl-c> to stop"
90
+ begin
91
+ encryptor.each_identifier do |eid|
92
+ puts "Quantum: #{encryptor.quantum}, EID: #{eid}"
93
+ end
94
+ rescue SignalException => e
95
+ # ignore CTRL-C, just exit
96
+ end
97
+ end
98
+ end
99
+
100
+ def track
101
+ beacon(true)
102
+ end
103
+
104
+ def eid
105
+ identity_key = ARGV.shift
106
+ rotation_scalar = ARGV.shift.to_i
107
+ beacon_time = (ARGV.shift || 0).to_i
108
+ encryptor = EphemeralCalc::Encryptor.new identity_key, rotation_scalar
109
+ quantum = beacon_time / 2**rotation_scalar
110
+ eid = encryptor.get_identifier(beacon_time)
111
+ puts "Identity Key: #{identity_key}"
112
+ puts " Beacon Time: #{beacon_time}"
113
+ puts " Quantum: #{quantum}"
114
+ puts "Ephemeral ID: #{eid}"
115
+ end
116
+
117
+ def list
118
+ identity_key = ARGV.shift
119
+ rotation_scalar = ARGV.shift.to_i
120
+ beacon_time = ARGV.shift.to_i
121
+ count = ARGV.shift.to_i
122
+ encryptor = EphemeralCalc::Encryptor.new identity_key, rotation_scalar
123
+ start_quantum = beacon_time / 2**rotation_scalar
124
+ end_quantum = start_quantum + count - 1
125
+ start_quantum.upto(end_quantum) do |quantum|
126
+ start_time = quantum * 2**rotation_scalar
127
+ end_time = start_time + 2**rotation_scalar
128
+ eid = encryptor.get_identifier(start_time)
129
+ puts "EID: #{eid}, Quantum: #{quantum} (#{seconds_display(start_time)} - #{seconds_display(end_time)})"
130
+ end
131
+ end
132
+
133
+ def resolve
134
+ require 'yaml'
135
+ eid_hex = ARGV.shift
136
+ api_key = ENV["GOOGLE_API_KEY"]
137
+
138
+ if api_key
139
+ client = EphemeralCalc::GoogleAPI::Client.new(nil) # don't try oauth
140
+ response = client.getforobserved(eid_hex, api_key)
141
+ beacons = response["beacons"]
142
+ beacon = beacons[0] if beacons
143
+ else
144
+ beacon_name = "beacons/4!#{eid_hex.downcase}"
145
+ begin
146
+ beacon = oauth_client.get_resource(beacon_name)
147
+ attachments = oauth_client.get_resource("#{beacon_name}/attachments")
148
+ beacon.merge!(attachments)
149
+ rescue EphemeralCalc::GoogleAPI::RequestError => e
150
+ # if we get a 404, the EID doesn't resolve
151
+ raise e unless e.code == 404
152
+ end
153
+ end
154
+
155
+ if beacon == nil
156
+ puts "Does not resolve!"
157
+ else
158
+ puts beacon.to_yaml
159
+ end
160
+ end
161
+
162
+ def eidparams
163
+ require 'yaml'
164
+ eidparams = oauth_client.eidparams
165
+ key_hex = to_hex(Base64.decode64(eidparams["serviceEcdhPublicKey"]))
166
+ eidparams["serviceEcdhPublicKeyHex"] = key_hex
167
+ puts eidparams.to_yaml
168
+ end
169
+
170
+ def to_hex(bytes)
171
+ bytes.unpack("H*")[0].upcase
172
+ end
173
+
174
+ def from_hex(hex)
175
+ [hex].pack("H*")
176
+ end
177
+
178
+ def register
179
+ require 'yaml'
180
+ beacon_public_key = from_hex(ARGV.shift)
181
+ rotation_scaler = ARGV.shift
182
+ initial_eid = from_hex(ARGV.shift)
183
+ initial_clock = ARGV.shift
184
+ namespace = from_hex(ARGV.shift)
185
+ instance = from_hex(ARGV.shift)
186
+ uid_bytes = namespace + instance
187
+ response = oauth_client.register_eid(beacon_public_key, rotation_scaler, initial_eid, initial_clock, uid_bytes)
188
+ puts response.to_yaml
189
+ end
190
+
191
+ def keygen
192
+ key_pair = EphemeralCalc::KeyPair.new
193
+ puts "Private Key: #{to_hex(key_pair.private_key)}"
194
+ puts " Public Key: #{to_hex(key_pair.public_key)}"
195
+ end
196
+
197
+ def seconds_display(seconds)
198
+ case
199
+ when seconds >= 86400
200
+ "#{seconds / 86400}d " + seconds_display(seconds % 86400)
201
+ when seconds >= 3600
202
+ "#{seconds / 3600}h " + seconds_display(seconds % 3600)
203
+ when seconds >= 60
204
+ "#{seconds / 60}m " + seconds_display(seconds % 60)
205
+ else
206
+ "#{seconds}s"
207
+ end
208
+ end
209
+
210
+ def oauth_client
211
+ @oauth_client ||=
212
+ begin
213
+ client = EphemeralCalc::GoogleAPI::Client.new
214
+ client.credentials.save
215
+ client
216
+ end
217
+ end
218
+ end
219
+
220
+ app = App.new
221
+ command = ARGV.shift
222
+
223
+ if command && App::COMMANDS.include?(command.to_sym)
224
+ app.send(command)
225
+ else
226
+ app.help
227
+ end