Compare commits
4 commits
b79c954d3b
...
212524429f
Author | SHA1 | Date | |
---|---|---|---|
|
212524429f | ||
|
455a00ecc0 | ||
|
38bbeceab4 | ||
|
42cec427a8 |
9 changed files with 87 additions and 55 deletions
10
Gemfile
10
Gemfile
|
@ -28,8 +28,7 @@ gem 'bootsnap', '>= 1.4.4', require: false
|
||||||
gem 'ssh_data'
|
gem 'ssh_data'
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
|
gem 'pry'
|
||||||
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
|
@ -46,11 +45,8 @@ group :development do
|
||||||
end
|
end
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
# Adds support for Capybara system testing and selenium driver
|
gem 'database_cleaner'
|
||||||
gem 'capybara', '>= 3.26'
|
gem 'factory_bot'
|
||||||
gem 'selenium-webdriver'
|
|
||||||
# Easy installation and use of web drivers to run system tests with browsers
|
|
||||||
gem 'webdrivers'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
||||||
|
|
45
Gemfile.lock
45
Gemfile.lock
|
@ -60,8 +60,6 @@ GEM
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
tzinfo (~> 2.0)
|
tzinfo (~> 2.0)
|
||||||
zeitwerk (~> 2.3)
|
zeitwerk (~> 2.3)
|
||||||
addressable (2.8.0)
|
|
||||||
public_suffix (>= 2.0.2, < 5.0)
|
|
||||||
ast (2.4.2)
|
ast (2.4.2)
|
||||||
bcrypt (3.1.17-x86_64-linux-musl)
|
bcrypt (3.1.17-x86_64-linux-musl)
|
||||||
bindex (0.8.1-x86_64-linux-musl)
|
bindex (0.8.1-x86_64-linux-musl)
|
||||||
|
@ -74,20 +72,16 @@ GEM
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
brakeman (5.2.1)
|
brakeman (5.2.1)
|
||||||
builder (3.2.4)
|
builder (3.2.4)
|
||||||
byebug (11.1.3-x86_64-linux-musl)
|
|
||||||
capybara (3.36.0)
|
|
||||||
addressable
|
|
||||||
matrix
|
|
||||||
mini_mime (>= 0.1.3)
|
|
||||||
nokogiri (~> 1.8)
|
|
||||||
rack (>= 1.6.0)
|
|
||||||
rack-test (>= 0.6.3)
|
|
||||||
regexp_parser (>= 1.5, < 3.0)
|
|
||||||
xpath (~> 3.2)
|
|
||||||
chartkick (4.1.3)
|
chartkick (4.1.3)
|
||||||
childprocess (4.1.0)
|
coderay (1.1.3)
|
||||||
concurrent-ruby (1.1.9)
|
concurrent-ruby (1.1.9)
|
||||||
crass (1.0.6)
|
crass (1.0.6)
|
||||||
|
database_cleaner (2.0.1)
|
||||||
|
database_cleaner-active_record (~> 2.0.0)
|
||||||
|
database_cleaner-active_record (2.0.1)
|
||||||
|
activerecord (>= 5.a)
|
||||||
|
database_cleaner-core (~> 2.0.0)
|
||||||
|
database_cleaner-core (2.0.1)
|
||||||
devise (4.8.1)
|
devise (4.8.1)
|
||||||
bcrypt (~> 3.0)
|
bcrypt (~> 3.0)
|
||||||
orm_adapter (~> 0.1)
|
orm_adapter (~> 0.1)
|
||||||
|
@ -101,6 +95,8 @@ GEM
|
||||||
exception_notification (4.5.0)
|
exception_notification (4.5.0)
|
||||||
actionmailer (>= 5.2, < 8)
|
actionmailer (>= 5.2, < 8)
|
||||||
activesupport (>= 5.2, < 8)
|
activesupport (>= 5.2, < 8)
|
||||||
|
factory_bot (6.2.1)
|
||||||
|
activesupport (>= 5.0.0)
|
||||||
ffi (1.15.5-x86_64-linux-musl)
|
ffi (1.15.5-x86_64-linux-musl)
|
||||||
globalid (1.0.0)
|
globalid (1.0.0)
|
||||||
activesupport (>= 5.0)
|
activesupport (>= 5.0)
|
||||||
|
@ -123,7 +119,6 @@ GEM
|
||||||
mail (2.7.1)
|
mail (2.7.1)
|
||||||
mini_mime (>= 0.1.1)
|
mini_mime (>= 0.1.1)
|
||||||
marcel (1.0.2)
|
marcel (1.0.2)
|
||||||
matrix (0.4.2)
|
|
||||||
method_source (1.0.0)
|
method_source (1.0.0)
|
||||||
mini_mime (1.1.2)
|
mini_mime (1.1.2)
|
||||||
mini_portile2 (2.8.0)
|
mini_portile2 (2.8.0)
|
||||||
|
@ -138,7 +133,9 @@ GEM
|
||||||
parser (3.1.1.0)
|
parser (3.1.1.0)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
pg (1.3.4-x86_64-linux-musl)
|
pg (1.3.4-x86_64-linux-musl)
|
||||||
public_suffix (4.0.6)
|
pry (0.14.1)
|
||||||
|
coderay (~> 1.1)
|
||||||
|
method_source (~> 1.0)
|
||||||
puma (5.6.2-x86_64-linux-musl)
|
puma (5.6.2-x86_64-linux-musl)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
racc (1.6.0-x86_64-linux-musl)
|
racc (1.6.0-x86_64-linux-musl)
|
||||||
|
@ -199,7 +196,6 @@ GEM
|
||||||
rubocop-ast (1.16.0)
|
rubocop-ast (1.16.0)
|
||||||
parser (>= 3.1.1.0)
|
parser (>= 3.1.1.0)
|
||||||
ruby-progressbar (1.11.0)
|
ruby-progressbar (1.11.0)
|
||||||
rubyzip (2.3.2)
|
|
||||||
safely_block (0.3.0)
|
safely_block (0.3.0)
|
||||||
errbase (>= 0.1.1)
|
errbase (>= 0.1.1)
|
||||||
sass-rails (6.0.0)
|
sass-rails (6.0.0)
|
||||||
|
@ -212,10 +208,6 @@ GEM
|
||||||
sprockets (> 3.0)
|
sprockets (> 3.0)
|
||||||
sprockets-rails
|
sprockets-rails
|
||||||
tilt
|
tilt
|
||||||
selenium-webdriver (4.1.0)
|
|
||||||
childprocess (>= 0.5, < 5.0)
|
|
||||||
rexml (~> 3.2, >= 3.2.5)
|
|
||||||
rubyzip (>= 1.2.2)
|
|
||||||
semantic_range (3.0.0)
|
semantic_range (3.0.0)
|
||||||
spring (4.0.0)
|
spring (4.0.0)
|
||||||
sprockets (4.0.3)
|
sprockets (4.0.3)
|
||||||
|
@ -241,10 +233,6 @@ GEM
|
||||||
activemodel (>= 6.0.0)
|
activemodel (>= 6.0.0)
|
||||||
bindex (>= 0.4.0)
|
bindex (>= 0.4.0)
|
||||||
railties (>= 6.0.0)
|
railties (>= 6.0.0)
|
||||||
webdrivers (5.0.0)
|
|
||||||
nokogiri (~> 1.6)
|
|
||||||
rubyzip (>= 1.3.0)
|
|
||||||
selenium-webdriver (~> 4.0)
|
|
||||||
webpacker (5.4.3)
|
webpacker (5.4.3)
|
||||||
activesupport (>= 5.2)
|
activesupport (>= 5.2)
|
||||||
rack-proxy (>= 0.6.1)
|
rack-proxy (>= 0.6.1)
|
||||||
|
@ -253,8 +241,6 @@ GEM
|
||||||
websocket-driver (0.7.5-x86_64-linux-musl)
|
websocket-driver (0.7.5-x86_64-linux-musl)
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
websocket-extensions (0.1.5)
|
websocket-extensions (0.1.5)
|
||||||
xpath (3.2.0)
|
|
||||||
nokogiri (~> 1.8)
|
|
||||||
zeitwerk (2.5.4)
|
zeitwerk (2.5.4)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
|
@ -265,27 +251,26 @@ DEPENDENCIES
|
||||||
blazer
|
blazer
|
||||||
bootsnap (>= 1.4.4)
|
bootsnap (>= 1.4.4)
|
||||||
brakeman
|
brakeman
|
||||||
byebug
|
database_cleaner
|
||||||
capybara (>= 3.26)
|
|
||||||
devise
|
devise
|
||||||
devise-i18n
|
devise-i18n
|
||||||
exception_notification
|
exception_notification
|
||||||
|
factory_bot
|
||||||
jbuilder (~> 2.7)
|
jbuilder (~> 2.7)
|
||||||
listen (~> 3.3)
|
listen (~> 3.3)
|
||||||
lograge
|
lograge
|
||||||
pg (~> 1.1)
|
pg (~> 1.1)
|
||||||
|
pry
|
||||||
puma (~> 5.0)
|
puma (~> 5.0)
|
||||||
rack-mini-profiler (~> 2.0)
|
rack-mini-profiler (~> 2.0)
|
||||||
rails (~> 6.1.4)
|
rails (~> 6.1.4)
|
||||||
rubocop
|
rubocop
|
||||||
sass-rails (>= 6)
|
sass-rails (>= 6)
|
||||||
selenium-webdriver
|
|
||||||
spring
|
spring
|
||||||
ssh_data
|
ssh_data
|
||||||
turbolinks (~> 5)
|
turbolinks (~> 5)
|
||||||
tzinfo-data
|
tzinfo-data
|
||||||
web-console (>= 4.1.0)
|
web-console (>= 4.1.0)
|
||||||
webdrivers
|
|
||||||
webpacker (~> 5.0)
|
webpacker (~> 5.0)
|
||||||
|
|
||||||
RUBY VERSION
|
RUBY VERSION
|
||||||
|
|
|
@ -16,12 +16,15 @@ class ReadingsController < ActionController::API
|
||||||
reading.id = params[:transaction_uuid]
|
reading.id = params[:transaction_uuid]
|
||||||
reading.signature = request.headers[:'X-Signature']
|
reading.signature = request.headers[:'X-Signature']
|
||||||
reading.raw_transaction = request.raw_post
|
reading.raw_transaction = request.raw_post
|
||||||
reading.verified = reading.verify_ssh_signature
|
reading.raw_transaction << "\n"
|
||||||
|
reading.verified = reading.verify(public_key)
|
||||||
|
|
||||||
params[:arduinos]&.each do |a|
|
params[:arduinos]&.reject do |a|
|
||||||
|
a[:id].blank? || a[:sensores].empty?
|
||||||
|
end&.each do |a|
|
||||||
arduino = reading.arduinos.build local_id: a[:id], raspberry: raspberry
|
arduino = reading.arduinos.build local_id: a[:id], raspberry: raspberry
|
||||||
|
|
||||||
a[:sensores]&.each do |s|
|
a[:sensores].each do |s|
|
||||||
arduino.sensors.build(sensor_params s)
|
arduino.sensors.build(sensor_params s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -55,11 +58,14 @@ class ReadingsController < ActionController::API
|
||||||
r.name = params[:controller_id]
|
r.name = params[:controller_id]
|
||||||
r.serial_number = params[:serial_number]
|
r.serial_number = params[:serial_number]
|
||||||
r.save
|
r.save
|
||||||
r.public_keys.find_or_create_by(content: params[:public_key])
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def public_key
|
||||||
|
@public_key ||= SSHData::PublicKey.parse_openssh(raspberry.public_keys.find_or_create_by(content: params[:public_key]).content)
|
||||||
|
end
|
||||||
|
|
||||||
# Procesa la transacción
|
# Procesa la transacción
|
||||||
def reading_params
|
def reading_params
|
||||||
@reading_params ||= params.permit(:timestamp,
|
@reading_params ||= params.permit(:timestamp,
|
||||||
|
|
|
@ -3,9 +3,11 @@
|
||||||
class Reading < ApplicationRecord
|
class Reading < ApplicationRecord
|
||||||
belongs_to :raspberry
|
belongs_to :raspberry
|
||||||
has_many :arduinos
|
has_many :arduinos
|
||||||
|
has_many :sensors, through: :arduinos
|
||||||
|
|
||||||
def verify_ssh_signature
|
# @param :public_key [SSHData::PublicKey]
|
||||||
ssh_signature.verify raw_transaction
|
def verify(public_key)
|
||||||
|
public_key == ssh_signature.public_key && ssh_signature.verify(raw_transaction)
|
||||||
rescue SSHData::Error
|
rescue SSHData::Error
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
42
test/controllers/readings_controller_test.rb
Normal file
42
test/controllers/readings_controller_test.rb
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ReadingsControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
setup do
|
||||||
|
@reading = JSON.parse(File.read(Rails.root.join(*%w[test fixtures files 20220318165621-565ca662-a6dc-11ec-95a5-574e273d29ba])))
|
||||||
|
@signature = File.read(Rails.root.join(*%w[test fixtures files 20220318165621-565ca662-a6dc-11ec-95a5-574e273d29ba.sig])).split("\n").tap do |s|
|
||||||
|
s.pop
|
||||||
|
s.reverse!
|
||||||
|
s.pop
|
||||||
|
s.reverse!
|
||||||
|
end.join('')
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'se puede probar la conexión' do
|
||||||
|
post readings_url, as: :json
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'se pueden enviar lecturas' do
|
||||||
|
post readings_url, as: :json, headers: {
|
||||||
|
'X-Signature': @signature
|
||||||
|
}, params: @reading
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal @reading['transaction_uuid'], response.body
|
||||||
|
assert (reading = Reading.find(response.body))
|
||||||
|
|
||||||
|
assert reading.raspberry
|
||||||
|
assert_equal @reading['controller_id'], reading.raspberry.name
|
||||||
|
assert_equal @reading['serial_number'], reading.raspberry.serial_number
|
||||||
|
|
||||||
|
assert_equal 1, reading.arduinos.count
|
||||||
|
assert_equal 2, reading.sensors.count
|
||||||
|
|
||||||
|
# XXX: Este JSON no se puede verificar porque hay espacios en el
|
||||||
|
# original que no llegaron con el envío a través de params
|
||||||
|
assert_not reading.verified
|
||||||
|
end
|
||||||
|
end
|
1
test/fixtures/files/20220318165621-565ca662-a6dc-11ec-95a5-574e273d29ba
vendored
Normal file
1
test/fixtures/files/20220318165621-565ca662-a6dc-11ec-95a5-574e273d29ba
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"transaction_uuid":"565ca662-a6dc-11ec-95a5-574e273d29ba","serial_number":"0000000083a999fd","public_key":"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBC30/zzdbYNJGOaIhnXllJ15OjXmBh/hVhQFJ1DKHMGuDqFJ1iW+QJhwJFWdYLvN64FNplM0wOP7Ibg+T/0sUcQ= Taller_RND 0000000083a999fd","controller_id":"Taller_RND","timestamp":"1647622581","error_code":"10","coordinates":{"lat":1,"lng":1},"battery_status":"98","sample":"0","storage":"uso del almacenamiento","arduinos":[ { "id":"0x01", "sensores": [ { "type": "hum", "value": 78, "unit": "P", "error": 99 }, { "type": "pre", "value": 100, "unit": "Hpa", "error": 98 }]}, { "id":"", "sensores": []}]}
|
7
test/fixtures/files/20220318165621-565ca662-a6dc-11ec-95a5-574e273d29ba.sig
vendored
Normal file
7
test/fixtures/files/20220318165621-565ca662-a6dc-11ec-95a5-574e273d29ba.sig
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
-----BEGIN SSH SIGNATURE-----
|
||||||
|
U1NIU0lHAAAAAQAAAGgAAAATZWNkc2Etc2hhMi1uaXN0cDI1NgAAAAhuaXN0cDI1NgAAAE
|
||||||
|
EELfT/PN1tg0kY5oiGdeWUnXk6NeYGH+FWFAUnUMocwa4OoUnWJb5AmHAkVZ1gu83rgU2m
|
||||||
|
UzTA4/shuD5P/SxRxAAAAARmaWxlAAAAAAAAAAZzaGE1MTIAAABkAAAAE2VjZHNhLXNoYT
|
||||||
|
ItbmlzdHAyNTYAAABJAAAAIASFthCP5MwCvt6lPLtv14U0IPPoTIsdceySf1SUfE8WAAAA
|
||||||
|
IQDN2bI/hkbvS2W+5Qta+gwFMKtB6ZPMaXSF4o/XWf5sCA==
|
||||||
|
-----END SSH SIGNATURE-----
|
11
test/fixtures/users.yml
vendored
11
test/fixtures/users.yml
vendored
|
@ -1,11 +0,0 @@
|
||||||
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
|
|
||||||
|
|
||||||
# This model initially had no columns defined. If you add columns to the
|
|
||||||
# model remove the '{}' from the fixture names and add the columns immediately
|
|
||||||
# below each fixture, per the syntax in the comments below
|
|
||||||
#
|
|
||||||
one: {}
|
|
||||||
# column: value
|
|
||||||
#
|
|
||||||
two: {}
|
|
||||||
# column: value
|
|
|
@ -10,4 +10,8 @@ class ActiveSupport::TestCase
|
||||||
fixtures :all
|
fixtures :all
|
||||||
|
|
||||||
# Add more helper methods to be used by all tests here...
|
# Add more helper methods to be used by all tests here...
|
||||||
|
DatabaseCleaner.strategy = :transaction
|
||||||
|
|
||||||
|
setup { DatabaseCleaner.start }
|
||||||
|
teardown { DatabaseCleaner.clean }
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue