et_fake_ccd 0.1.4

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d996e2ecc6506b06423a803d8cb7c036bae2ed22d54b54086116f62b414329b4
4
+ data.tar.gz: e4b5f5dd49121964b0c743dfacb090566a630781a15503ca9a605a25ae0cde7b
5
+ SHA512:
6
+ metadata.gz: 8f3e6d33de764179d52834d5e8e220715d636363afe38906ef5e13b42a6828f25d08f39057477998834425e495fd8ad0b6c775fe334047a3b8d965b5ee774445
7
+ data.tar.gz: a71cbf6ba8b02e9e280596cb2d101422ad2a8c6d965e9f89aba15ea5eb389801c8da48191cdcab3c703a8b015ad925b554b424e4b60071742980d65fd87fd31e
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+ /.idea
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ sudo: false
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.5.1
6
+ before_install: gem install bundler -v 2.0.2
7
+ deploy:
8
+ provider: rubygems
9
+ api_key:
10
+ secure: 4Pj0uTaPtr1fpqlkiEunQ3qhyc1CycWX9bnLwXI4kfLffmqeYzWguZf6fDX6d8QcFxbFBInmgKII0Ps6ee2KsB6q1DE2B1/J5CXVZZcGYy25d4qa5mUWHDGaX85NZUOEQBN/+RZtDMJKbT9d0CkiLXS4XLOJxdADSIwe2y8I2pnZwJEO2F+eJxXW258JLJV/yybWhY7ACyWsTSLEAY4yq+fIQVM81tvoXbu2j+l+nWXeIud26axT3dQhwT34zO7MYM32zj/xYF8mfzPbTaoaRHlVSR/P5ABv7TakbZ22YT940iLqNjq+rSaDCS0q/XnYLGpREMEZZ9LO10AdeU3Vv+c5jg+n9sY2gxzYywneB3MP8x85EX27esnQIO+dr37wCsx7iPa8Ef4RJ+BTl59PBHX0JJbiiNtJvZu1KVaPjrMxmOW9WSXCzh6fQuFdcCfBJQhrSqighkk7znF1LJ6cZcmjteg/5kv3a4QdTqATjclp5wI5JvSR6GGmc9QGuqGqEwUMSvBUExDCoes9NcLBOqOpZP387kZSZWo6TJ6P2mSi/KZ93iuEHmYraaaTwjfMHsXFmrEYPA+AgKawN9a58M/DkVoDQg7og6/c8aNK06CLZa/d8lOM7ZajNf/Adndt3j9gsqyo9Zcn35L6Zy9+CkhTfeXeAz+fmbhn2ZM/UK0=
11
+ on:
12
+ tags: true
13
+ gem: et_fake_ccd
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in et_fake_ccd.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,64 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ et_fake_ccd (0.1.4)
5
+ activemodel (~> 5.2, >= 5.2.3)
6
+ roda (~> 3.21)
7
+ rotp (~> 5.1)
8
+ thor (~> 0.20.3)
9
+ tilt (~> 2.0, >= 2.0.9)
10
+
11
+ GEM
12
+ remote: https://rubygems.org/
13
+ specs:
14
+ activemodel (5.2.3)
15
+ activesupport (= 5.2.3)
16
+ activesupport (5.2.3)
17
+ concurrent-ruby (~> 1.0, >= 1.0.2)
18
+ i18n (>= 0.7, < 2)
19
+ minitest (~> 5.1)
20
+ tzinfo (~> 1.1)
21
+ addressable (2.6.0)
22
+ public_suffix (>= 2.0.2, < 4.0)
23
+ concurrent-ruby (1.1.5)
24
+ diff-lcs (1.3)
25
+ i18n (1.6.0)
26
+ concurrent-ruby (~> 1.0)
27
+ minitest (5.11.3)
28
+ public_suffix (3.1.1)
29
+ rack (2.0.7)
30
+ rake (10.5.0)
31
+ roda (3.21.0)
32
+ rack
33
+ rotp (5.1.0)
34
+ addressable (~> 2.5)
35
+ rspec (3.8.0)
36
+ rspec-core (~> 3.8.0)
37
+ rspec-expectations (~> 3.8.0)
38
+ rspec-mocks (~> 3.8.0)
39
+ rspec-core (3.8.1)
40
+ rspec-support (~> 3.8.0)
41
+ rspec-expectations (3.8.4)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.8.0)
44
+ rspec-mocks (3.8.1)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.8.0)
47
+ rspec-support (3.8.2)
48
+ thor (0.20.3)
49
+ thread_safe (0.3.6)
50
+ tilt (2.0.9)
51
+ tzinfo (1.2.5)
52
+ thread_safe (~> 0.1)
53
+
54
+ PLATFORMS
55
+ ruby
56
+
57
+ DEPENDENCIES
58
+ bundler (~> 2.0)
59
+ et_fake_ccd!
60
+ rake (~> 10.0)
61
+ rspec (~> 3.0)
62
+
63
+ BUNDLED WITH
64
+ 2.0.2
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Gary Taylor
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # EtFakeCcd
2
+
3
+ This gem can either be used as part of a test suite, providing a rack endpoint which can be loaded using
4
+ webmock.
5
+
6
+ OR
7
+
8
+ It can be used as a standalone server
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'et_fake_ccd'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install et_fake_ccd
25
+
26
+ ## Usage
27
+
28
+ TODO: Write usage instructions here
29
+
30
+ ## Development
31
+
32
+ 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.
33
+
34
+ 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).
35
+
36
+ ## Contributing
37
+
38
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/et_fake_ccd.
39
+
40
+ ## License
41
+
42
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "et_fake_ccd"
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(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,35 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "et_fake_ccd/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "et_fake_ccd"
8
+ spec.version = EtFakeCcd::VERSION
9
+ spec.authors = ["Gary Taylor"]
10
+ spec.email = ["gary.taylor@hmcts.net"]
11
+
12
+ spec.summary = %q{Fake CCD server for employment tribunals}
13
+ spec.description = %q{Fake CCD server for employment tribunals}
14
+ spec.homepage = "https://github.com/hmcts/et-fake-ccd"
15
+ spec.license = "MIT"
16
+
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ end
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+
26
+ spec.add_dependency 'roda', '~> 3.21'
27
+ spec.add_dependency 'thor', '~> 0.20.3'
28
+ spec.add_dependency 'activemodel', '~> 5.2', '>= 5.2.3'
29
+ spec.add_dependency 'rotp', '~> 5.1'
30
+ spec.add_dependency 'tilt', '~> 2.0', '>= 2.0.9'
31
+
32
+ spec.add_development_dependency "bundler", "~> 2.0"
33
+ spec.add_development_dependency "rake", "~> 10.0"
34
+ spec.add_development_dependency "rspec", "~> 3.0"
35
+ end
data/exe/et_fake_ccd ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "et_fake_ccd"
4
+ require "et_fake_ccd/cli"
5
+ EtFakeCcd::Cli::Root.start(ARGV)
@@ -0,0 +1,14 @@
1
+ require "et_fake_ccd/version"
2
+ require "et_fake_ccd/config"
3
+ require "et_fake_ccd/root_app"
4
+ require "et_fake_ccd/service/sidam_app"
5
+
6
+ module EtFakeCcd
7
+ class Error < StandardError; end
8
+ # Your code goes here...
9
+ #
10
+ def self.config
11
+ Config.instance
12
+ end
13
+ end
14
+
@@ -0,0 +1,44 @@
1
+ require "singleton"
2
+ module EtFakeCcd
3
+ class AuthService
4
+ include Singleton
5
+
6
+ attr_reader :service_token, :user_token
7
+
8
+ def self.generate_service_token
9
+ instance.generate_service_token
10
+ end
11
+
12
+ def self.generate_user_token
13
+ instance.generate_user_token
14
+ end
15
+
16
+ def self.validate_service_token(token)
17
+ instance.validate_service_token(token)
18
+ end
19
+
20
+ def self.validate_user_token(token)
21
+ instance.validate_user_token(token)
22
+ end
23
+
24
+ def generate_service_token
25
+ self.service_token = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJjY2RfZ3ciLCJleHAiOjE1NjE3NDIzMDN9.u9e1iGfAhXFsmGa4TbJBpnQ3Pps5Kdj64zPZELwEHqdSmMjWcDFaX1psf43QIKREB-7SU09oDBFTlcdJMxvOJw"
26
+ end
27
+
28
+ def generate_user_token
29
+ self.user_token = "eyJ0eXAiOiJKV1QiLCJ6aXAiOiJOT05FIiwia2lkIjoiS0N4QmRlaHNIVUY2OTc4U2l6dklTRXhjWDBFPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJlcmljLmNjZGNvb3BlckBnbWFpbC5jb20iLCJhdXRoX2xldmVsIjowLCJhdWRpdFRyYWNraW5nSWQiOiI4NTg5NTc1OC1mMDg2LTRmMjgtYWIzOS1hNDBkNmE4YmRkYjciLCJpc3MiOiJodHRwczovL2Zvcmdlcm9jay1hbS5zZXJ2aWNlLmNvcmUtY29tcHV0ZS1pZGFtLWRlbW8uaW50ZXJuYWw6ODQ0My9vcGVuYW0vb2F1dGgyL2htY3RzIiwidG9rZW5OYW1lIjoiYWNjZXNzX3Rva2VuIiwidG9rZW5fdHlwZSI6IkJlYXJlciIsImF1dGhHcmFudElkIjoiN2ZiZTM3ZWEtZTc4Ni00ZTM1LWE3MzgtNThkMjRkOGZiNzlhIiwiYXVkIjoiaG1jdHMiLCJuYmYiOjE1NjE3MzQ0NjQsImdyYW50X3R5cGUiOiJwYXNzd29yZCIsInNjb3BlIjpbImFjciIsIm9wZW5pZCIsInByb2ZpbGUiLCJyb2xlcyIsImF1dGhvcml0aWVzIl0sImF1dGhfdGltZSI6MTU2MTczNDQ2NCwicmVhbG0iOiIvaG1jdHMiLCJleHAiOjE1NjE3NjMyNjQsImlhdCI6MTU2MTczNDQ2NCwiZXhwaXJlc19pbiI6Mjg4MDAsImp0aSI6ImRiNWI1ZTBlLWE1ODEtNGMwYi1iOGI1LTQxNGZmY2E3MWQzMyJ9.kZj0Y8h18MWde171myuGIPphijX9j2L2yhCUC75L3D-9fi11So-nlEOelh9-3jtolr9k--du9jzOREFy7KplsjLId6_yShd1CaafHz6DGvUBViO1vuoy6lp39R2iYfm5PEniLRDVVCySRkclLFtFaSQ3Ln28jo53BcLfTBXtH5gA_ydpgBaU6t66TZjWr_eu_mdSiFqdwWRFWsNJJiKQenZUXqcJiY9H1US6vx4RT3678HicZXNOCzg0_YIjtmZuMc3-akD6RLySch4qRy_ARWVjUzA_gAtz5R-R5MU6tGHJZpw_-leC4qwfVpTfEk2uTLOpLUSih6zYprzkkWyTJg"
30
+ end
31
+
32
+ def validate_service_token(token)
33
+ service_token == token
34
+ end
35
+
36
+ def validate_user_token(token)
37
+ user_token == token
38
+ end
39
+
40
+ private
41
+
42
+ attr_writer :service_token, :user_token
43
+ end
44
+ end
@@ -0,0 +1 @@
1
+ require "et_fake_ccd/cli/root"
@@ -0,0 +1,16 @@
1
+ require "thor"
2
+ module EtFakeCcd
3
+ module Cli
4
+ class Root < Thor
5
+ desc "start_multiple", "Run multiple services on different ports"
6
+ def start_multiple
7
+ puts "Not yet written"
8
+ end
9
+
10
+ desc "start", "Run multiple services on one port"
11
+ def start
12
+ Rack::Server.start app: EtFakeCcd::RootApp
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,44 @@
1
+ require 'active_model'
2
+ module EtFakeCcd
3
+ module Command
4
+ class CreateCaseCommand
5
+ include ActiveModel::Model
6
+ include ActiveModel::Attributes
7
+
8
+ SCHEMA_FILE = File.absolute_path(File.join('..', 'case_create.json'), __dir__)
9
+
10
+ attribute :data
11
+
12
+ def self.from_json(json)
13
+ new data: json
14
+ end
15
+
16
+ validate :validate_data
17
+
18
+ private
19
+
20
+ def validate_data
21
+ validate_claimant_type
22
+ validate_primary_claimant
23
+ end
24
+
25
+ def validate_claimant_type
26
+ data.dig('data', 'claimant_TypeOfClaimant').tap do |claimant_type|
27
+ errors.add :data, "Case data validation failed", field_error: { "id": "claimant_TypeOfClaimant", "message": "Wrong is not a valid value" } unless ['Individual', 'Company'].include?(claimant_type)
28
+ end
29
+ end
30
+ def validate_primary_claimant
31
+ data.dig('data', 'claimantType', 'claimant_phone_number').tap do |phone|
32
+ errors.add :data, "Case data validation failed", field_error: { id: "claimantType.claimant_phone_number", message: "The data entered is not valid for this type of field, please delete and re-enter using only valid data" } if phone.present? && phone.length > 14
33
+ end
34
+ data.dig('data', 'claimantType', 'claimant_mobile_number').tap do |phone|
35
+ errors.add :data, "Case data validation failed", field_error: { id: "claimantType.claimant_mobile_number", message: "The data entered is not valid for this type of field, please delete and re-enter using only valid data" } if phone.present? && phone.length > 14
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ #{"exception":"uk.gov.hmcts.ccd.endpoint.exceptions.CaseValidationException","timestamp":"2019-07-01T15:33:41.417","status":422,"error":"Unprocessable Entity","message":"Case data validation failed","path":"/caseworkers/22/jurisdictions/EMPLOYMENT/case-types/EmpTrib_MVP_1.0_Manc/cases","details":{"field_errors":[{"id":"claimantType.claimant_phone_number","message":"The data entered is not valid for this type of field, please delete and re-enter using only valid data"}]},"callbackErrors":null,"callbackWarnings":null}
43
+ #{"exception":"uk.gov.hmcts.ccd.endpoint.exceptions.CaseValidationException","timestamp":"2019-07-01T15:51:15.291","status":422,"error":"Unprocessable Entity","message":"Case data validation failed","path":"/caseworkers/22/jurisdictions/EMPLOYMENT/case-types/EmpTrib_MVP_1.0_Manc/cases","details":{"field_errors":[{"id":"claimantType.claimant_mobile_number","message":"The data entered is not valid for this type of field, please delete and re-enter using only valid data"},{"id":"claimantType.claimant_phone_number","message":"The data entered is not valid for this type of field, please delete and re-enter using only valid data"}]},"callbackErrors":null,"callbackWarnings":null}
44
+ #{"exception":"uk.gov.hmcts.ccd.endpoint.exceptions.CaseValidationException","timestamp":"2019-07-01T16:02:28.045","status":422,"error":"Unprocessable Entity","message":"Case data validation failed","path":"/caseworkers/22/jurisdictions/EMPLOYMENT/case-types/EmpTrib_MVP_1.0_Manc/cases","details":{"field_errors":[{"id":"claimant_TypeOfClaimant","message":"Wrong is not a valid value"},{"id":"claimantType.claimant_mobile_number","message":"The data entered is not valid for this type of field, please delete and re-enter using only valid data"},{"id":"claimantType.claimant_phone_number","message":"The data entered is not valid for this type of field, please delete and re-enter using only valid data"}]},"callbackErrors":null,"callbackWarnings":null}
@@ -0,0 +1,29 @@
1
+ require 'active_model'
2
+ require 'et_fake_ccd/validator/otp_validator.rb'
3
+ module EtFakeCcd
4
+ module Command
5
+ class LeaseCommand
6
+ include ActiveModel::Model
7
+ include ActiveModel::Attributes
8
+
9
+ def initialize(config: ::EtFakeCcd::Config.instance, **args)
10
+ self.config = config
11
+ super(**args)
12
+ end
13
+
14
+ attribute :one_time_password
15
+ attribute :microservice
16
+
17
+ def self.from_json(json)
18
+ new one_time_password: json['oneTimePassword'], microservice: json['microservice']
19
+ end
20
+
21
+ validates :one_time_password, "et_fake_ccd/validator/otp": { secret: EtFakeCcd::Config.instance.microservice_secret }
22
+
23
+ private
24
+
25
+ attr_accessor :config
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ require 'active_model'
2
+ module EtFakeCcd
3
+ module Command
4
+ class LoginUserCommand
5
+ include ActiveModel::Model
6
+ include ActiveModel::Attributes
7
+
8
+ def initialize(config: ::EtFakeCcd::Config.instance, **args)
9
+ self.config = config
10
+ super(**args)
11
+ end
12
+
13
+ attribute :username
14
+ attribute :password
15
+
16
+ def self.from_json(json)
17
+ new username: json['username'], password: json['password']
18
+ end
19
+
20
+ validate :validate_username_and_password
21
+
22
+ private
23
+
24
+ attr_accessor :config
25
+
26
+ def validate_username_and_password
27
+ return if config.valid_credentials.any? do |cred|
28
+ username == cred[:username] && password == cred[:password]
29
+ end
30
+ errors.add(:username, "Invalid username or password")
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,3 @@
1
+ require 'et_fake_ccd/command/lease_command'
2
+ require 'et_fake_ccd/command/login_user_command'
3
+ require 'et_fake_ccd/command/create_case_command'
@@ -0,0 +1,18 @@
1
+ require 'singleton'
2
+ module EtFakeCcd
3
+ class Config
4
+ include Singleton
5
+
6
+ attr_accessor :microservice, :microservice_secret, :valid_credentials, :oauth2_client_id, :oauth2_redirect_url
7
+ end
8
+
9
+ Config.instance.tap do |c|
10
+ c.microservice = 'ccd_gw'
11
+ c.microservice_secret = 'AAAAAAAAAAAAAAAC'
12
+ c.valid_credentials = [
13
+ {username: 'm@m.com', password: 'p'}
14
+ ]
15
+ c.oauth2_client_id = "ccd_gateway"
16
+ c.oauth2_redirect_url = "http://localhost:3451/oauth2redirect" # The contents of this at the moment are not important
17
+ end
18
+ end
@@ -0,0 +1,97 @@
1
+ require "singleton"
2
+ module EtFakeCcd
3
+ class DataStoreService
4
+ include Singleton
5
+ def self.store_case_data(json, jid:, ctid:)
6
+ instance.store_case_data(json, jid: jid, ctid: ctid)
7
+ end
8
+
9
+ def self.find_case_data_by_id(id, jid:, ctid:)
10
+ instance.find_case_data_by_id(id, jid: jid, ctid: ctid)
11
+ end
12
+
13
+ def self.list(jid:, ctid:, filters: {}, page: 1, sort_direction: 'asc', page_size: 25)
14
+ instance.list(jid: jid, ctid: ctid, filters: filters, page: page, sort_direction: sort_direction, page_size: page_size)
15
+ end
16
+
17
+ def store_case_data(json, jid:, ctid:)
18
+ adapter.store(json, jid: jid, ctid: ctid)
19
+ end
20
+
21
+ def find_case_data_by_id(id, jid:, ctid:)
22
+ adapter.fetch_by_id(id, jid: jid, ctid: ctid)
23
+ end
24
+
25
+ def list(jid:, ctid:, filters: {}, page: 1, sort_direction: 'asc', page_size: 25)
26
+ adapter.fetch_all(jid: jid, ctid: ctid, filters: filters, page: page, sort_direction: sort_direction, page_size: page_size)
27
+ end
28
+
29
+ def adapter
30
+ @adapter ||= InMemoryAdapter.new
31
+ end
32
+
33
+ class InMemoryAdapter
34
+ def initialize
35
+ self.data = {}
36
+ self.id = 10000000000
37
+ end
38
+
39
+ def store(json, jid:, ctid:)
40
+ self.id = id + 1
41
+ data[jid] ||= {}
42
+ data[jid][ctid] ||= {}
43
+ data[jid][ctid][id] = json
44
+ id
45
+ end
46
+
47
+ def fetch_by_id(id, jid:, ctid:)
48
+ data.dig(jid, ctid, id)
49
+ end
50
+
51
+ def fetch_all(jid:, ctid:, filters: {}, page: 1, sort_direction: 'asc', page_size: 25)
52
+ hash = data.dig(jid, ctid)
53
+ return [] if hash.nil? || hash.empty?
54
+
55
+ filtered_list = filter(hash, filters: filters)
56
+ sorted_list = sort(filtered_list, sort_direction: sort_direction)
57
+ paginate(sorted_list, page_size: page_size, page: page)
58
+ end
59
+
60
+ private
61
+
62
+ attr_accessor :data, :id
63
+
64
+ def filter(list, filters:)
65
+ return list if filters.nil? || filters.empty?
66
+
67
+ list.select do |id, item|
68
+ included?(item, filters: filters)
69
+ end
70
+ end
71
+
72
+ def sort(list, sort_direction:)
73
+ return list if sort_direction == 'asc'
74
+
75
+ list.sort {|l, r| r <=> l}
76
+ end
77
+
78
+ def included?(item, filters:)
79
+ filters.all? do |(key, value)|
80
+ get_attribute_by_json_path(item, key) == value
81
+ end
82
+ end
83
+
84
+ def get_attribute_by_json_path(item, key)
85
+ path = key.split('.')
86
+ path[0] = 'data' if path[0] == 'case'
87
+ item.dig(*path)
88
+ end
89
+
90
+ def paginate(list, page_size:, page:)
91
+ arr = list.to_a[page_size * (page - 1) .. (page_size * page) - 1]
92
+ arr.to_h
93
+ end
94
+
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,24 @@
1
+ require "roda"
2
+ require "et_fake_ccd/service/sidam_app"
3
+ require "et_fake_ccd/service/auth_app"
4
+ require "et_fake_ccd/service/data_store_app"
5
+ require "et_fake_ccd/service/ui_app"
6
+ require "et_fake_ccd/service/authentication_web_app"
7
+ require "et_fake_ccd/service/case_management_web_app"
8
+ require "et_fake_ccd/service/api_gateway_web_app"
9
+ module EtFakeCcd
10
+ class RootApp < Roda
11
+ plugin :multi_run
12
+ run "idam", Service::SidamApp
13
+ run "auth", Service::AuthApp
14
+ run "data_store", Service::DataStoreApp
15
+ run "ui", Service::UiApp
16
+ run "authentication-web", Service::AuthenticationWebApp
17
+ run "case-management-web", Service::CaseManagementWebApp
18
+ run "api-gateway", Service::ApiGatewayWebApp
19
+
20
+ route do |r|
21
+ r.multi_run
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,68 @@
1
+ require 'roda'
2
+ require 'json'
3
+ require 'et_fake_ccd/commands'
4
+ require 'et_fake_ccd/auth_service'
5
+ require 'et_fake_ccd/data_store_service'
6
+ module EtFakeCcd
7
+ module Service
8
+ class ApiGatewayWebApp < Roda
9
+ plugin :request_headers
10
+ plugin :halt
11
+ plugin :cookies
12
+ route do |r|
13
+ r.is "oauth2" do
14
+ r.get do
15
+ response.set_cookie('accessToken', 'eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJ1OHM3NXRiOGlmaWhicnVjYWQzcm41bDAwZiIsInN1YiI6IjIyIiwiaWF0IjoxNTYyMDU3OTk5LCJleHAiOjE1NjIwODY3OTksImRhdGEiOiJjYXNld29ya2VyLGNhc2V3b3JrZXItZW1wbG95bWVudC10cmlidW5hbC1tYW5jaGVzdGVyLWNhc2VvZmZpY2VyLGNhc2V3b3JrZXItZW1wbG95bWVudC10cmlidW5hbC1tYW5jaGVzdGVyLWNhc2VzdXBlcnZpc29yLGNhc2V3b3JrZXItZW1wbG95bWVudCxjYXNld29ya2VyLWVtcGxveW1lbnQtdHJpYnVuYWwtbWFuY2hlc3RlcixjYXNld29ya2VyLWVtcGxveW1lbnQtdHJpYnVuYWwtZ2xhc2dvdy1jYXNlb2ZmaWNlcixjYXNld29ya2VyLWVtcGxveW1lbnQtdHJpYnVuYWwtZ2xhc2dvdy1jYXNlc3VwZXJ2aXNvcixjYXNld29ya2VyLWVtcGxveW1lbnQtdHJpYnVuYWwtZ2xhc2dvdyxjYXNld29ya2VyLGNhc2V3b3JrZXItbG9hMSxjYXNld29ya2VyLWVtcGxveW1lbnQtdHJpYnVuYWwtbWFuY2hlc3Rlci1jYXNlb2ZmaWNlci1sb2ExLGNhc2V3b3JrZXItZW1wbG95bWVudC10cmlidW5hbC1tYW5jaGVzdGVyLWNhc2VzdXBlcnZpc29yLWxvYTEsY2FzZXdvcmtlci1lbXBsb3ltZW50LWxvYTEsY2FzZXdvcmtlci1lbXBsb3ltZW50LXRyaWJ1bmFsLW1hbmNoZXN0ZXItbG9hMSxjYXNld29ya2VyLWVtcGxveW1lbnQtdHJpYnVuYWwtZ2xhc2dvdy1jYXNlb2ZmaWNlci1sb2ExLGNhc2V3b3JrZXItZW1wbG95bWVudC10cmlidW5hbC1nbGFzZ293LWNhc2VzdXBlcnZpc29yLWxvYTEsY2FzZXdvcmtlci1lbXBsb3ltZW50LXRyaWJ1bmFsLWdsYXNnb3ctbG9hMSxjYXNld29ya2VyLWxvYTEiLCJ0eXBlIjoiQUNDRVNTIiwiaWQiOiIyMiIsImZvcmVuYW1lIjoiQnV6eiIsInN1cm5hbWUiOiJMaWdodHllYXIiLCJkZWZhdWx0LXNlcnZpY2UiOiJDQ0QiLCJsb2EiOjEsImRlZmF1bHQtdXJsIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6OTAwMC9wb2MvY2NkIiwiZ3JvdXAiOiJjYXNld29ya2VyIn0.9Ct8RRBQSjANN8PIvw-mVpfZSOxv8kg68yctRR0JC4M')
16
+ ""
17
+ end
18
+ end
19
+ r.on "aggregated" do
20
+ r.is "caseworkers", Integer, "jurisdictions", String, "case-types", String, "cases" do |uid, jid, ctid|
21
+ r.get do
22
+ filters = r.params.dup
23
+ page = (filters.delete('page') || "1").to_i
24
+ sort_direction = filters.delete('sortDirection') || 'asc'
25
+ list = DataStoreService.list(jid: jid, ctid: ctid, filters: filters, page: page, sort_direction: sort_direction, page_size: 25)
26
+ cases_response(list, uid, jid, ctid)
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def config
35
+ EtFakeCcd.config
36
+ end
37
+
38
+ def cases_response(list, uid, jid, ctid)
39
+ j = {
40
+ results: list.keys.map do |id|
41
+ case_hash(ctid, id, jid)
42
+ end
43
+ }
44
+ JSON.generate(j)
45
+ end
46
+
47
+ def case_hash(ctid, id, jid)
48
+ {
49
+ "id": id,
50
+ "jurisdiction": jid,
51
+ "state": "1_Submitted",
52
+ "case_type_id": ctid,
53
+ "created_date": "2019-07-01T09:37:37.936",
54
+ "last_modified": "2019-07-01T09:37:37.936",
55
+ "security_classification": "PUBLIC",
56
+ "case_fields": ::EtFakeCcd::DataStoreService.find_case_data_by_id(id, jid: jid, ctid: ctid)['data'],
57
+ "data_classification": {},
58
+ "after_submit_callback_response": nil,
59
+ "callback_response_status_code": nil,
60
+ "callback_response_status": nil,
61
+ "delete_draft_response_status_code": nil,
62
+ "delete_draft_response_status": nil,
63
+ "security_classifications": {}
64
+ }
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,36 @@
1
+ require 'roda'
2
+ require 'json'
3
+ require 'et_fake_ccd/commands'
4
+ require 'et_fake_ccd/auth_service'
5
+ module EtFakeCcd
6
+ module Service
7
+ class AuthApp < Roda
8
+ plugin :request_headers
9
+ plugin :halt
10
+ route do |r|
11
+ r.is "lease" do
12
+ r.post do
13
+ command = ::EtFakeCcd::Command::LeaseCommand.from_json JSON.parse(r.body.read)
14
+ if command.valid?
15
+ ::EtFakeCcd::AuthService.generate_service_token
16
+ else
17
+ r.halt 403, render_error_for(command)
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def render_error_for(command)
26
+ if command.errors.include?(:one_time_password)
27
+ {message: 'Invalid one-time password'}.to_json
28
+ else
29
+ {message: command.errors.map(&:message).join(', ') }
30
+ end
31
+ end
32
+
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,29 @@
1
+ require 'roda'
2
+ require 'json'
3
+ require 'et_fake_ccd/commands'
4
+ require 'et_fake_ccd/auth_service'
5
+ module EtFakeCcd
6
+ module Service
7
+ class AuthenticationWebApp < Roda
8
+ plugin :request_headers
9
+ plugin :halt
10
+ plugin :render
11
+ route do |r|
12
+ r.is "login" do
13
+ r.get do
14
+ render("login.html", locals: { oauth2_redirect_url: config.oauth2_redirect_url, oauth2_client_id: config.oauth2_client_id })
15
+ end
16
+ r.post do
17
+ r.redirect "/case-management-web/oauth2redirect?code=pfSHb6v4dEDEfqqP"
18
+ end
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def config
25
+ EtFakeCcd.config
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ require 'roda'
2
+ require 'json'
3
+ require 'et_fake_ccd/commands'
4
+ require 'et_fake_ccd/auth_service'
5
+ module EtFakeCcd
6
+ module Service
7
+ class CaseManagementWebApp < Roda
8
+ plugin :request_headers
9
+ plugin :halt
10
+ plugin :render
11
+ route do |r|
12
+ r.is "oauth2redirect" do
13
+ r.get do
14
+ ""
15
+ end
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def config
22
+ EtFakeCcd.config
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,134 @@
1
+ require 'roda'
2
+ require 'json'
3
+ require 'et_fake_ccd/commands'
4
+ require 'et_fake_ccd/auth_service'
5
+ require 'et_fake_ccd/data_store_service'
6
+ module EtFakeCcd
7
+ module Service
8
+ class DataStoreApp < Roda
9
+ plugin :request_headers
10
+ plugin :halt
11
+ route do |r|
12
+ r.is "caseworkers", Integer, "jurisdictions", String, "case-types", String, "event-triggers", "initiateCase", "token" do |uid, jid, ctid|
13
+ r.get do
14
+ if EtFakeCcd::AuthService.validate_service_token(r.headers['ServiceAuthorization'].gsub(/\ABearer /, '')) && EtFakeCcd::AuthService.validate_user_token(r.headers['Authorization'].gsub(/\ABearer /, ''))
15
+ initiate_case(uid, jid, ctid)
16
+ else
17
+ r.halt 403, forbidden_error_for(r)
18
+ end
19
+ end
20
+ end
21
+ r.is "caseworkers", Integer, "jurisdictions", String, "case-types", String, "cases" do |uid, jid, ctid|
22
+ r.post do
23
+ if !EtFakeCcd::AuthService.validate_service_token(r.headers['ServiceAuthorization'].gsub(/\ABearer /, '')) || !EtFakeCcd::AuthService.validate_user_token(r.headers['Authorization'].gsub(/\ABearer /, ''))
24
+ r.halt 403, forbidden_error_for(r)
25
+ break
26
+ end
27
+ json = JSON.parse(r.body.read)
28
+ command = ::EtFakeCcd::Command::CreateCaseCommand.from_json json
29
+ if command.valid?
30
+ id = ::EtFakeCcd::DataStoreService.store_case_data(json, jid: jid, ctid: ctid)
31
+ case_created_response(id, uid, jid, ctid)
32
+ else
33
+ r.halt 422, render_error_for(command, r)
34
+ end
35
+ end
36
+
37
+ r.get do
38
+ if !EtFakeCcd::AuthService.validate_service_token(r.headers['ServiceAuthorization'].gsub(/\ABearer /, '')) || !EtFakeCcd::AuthService.validate_user_token(r.headers['Authorization'].gsub(/\ABearer /, ''))
39
+ r.halt 403, forbidden_error_for(r)
40
+ break
41
+ end
42
+ filters = r.params.dup
43
+ page = (filters.delete('page') || "1").to_i
44
+ sort_direction = filters.delete('sortDirection') || 'asc'
45
+ list = DataStoreService.list(jid: jid, ctid: ctid, filters: filters, page: page, sort_direction: sort_direction, page_size: 25)
46
+ cases_response(list, uid, jid, ctid)
47
+ end
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def initiate_case(uid, jid, ctid)
54
+ j = {
55
+ "token": "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJvZDRwZ3NhbDQwcTdndHI0Y2F1bmVmZGU5aSIsInN1YiI6IjIyIiwiaWF0IjoxNTYxOTY2NzM1LCJldmVudC1pZCI6ImluaXRpYXRlQ2FzZSIsImNhc2UtdHlwZS1pZCI6IkVtcFRyaWJfTVZQXzEuMF9NYW5jIiwianVyaXNkaWN0aW9uLWlkIjoiRU1QTE9ZTUVOVCIsImNhc2UtdmVyc2lvbiI6ImJmMjFhOWU4ZmJjNWEzODQ2ZmIwNWI0ZmEwODU5ZTA5MTdiMjIwMmYifQ.u-OfexKFu52uvSgTNVHJ5kUQ9KTZGClRIRnGXRPSmGY",
56
+ "case_details": {
57
+ "id": nil,
58
+ "jurisdiction": jid,
59
+ "state": nil,
60
+ "case_type_id": ctid,
61
+ "created_date": nil,
62
+ "last_modified": nil,
63
+ "security_classification": nil,
64
+ "case_data": {},
65
+ "data_classification": {},
66
+ "after_submit_callback_response": nil,
67
+ "callback_response_status_code": nil,
68
+ "callback_response_status": nil,
69
+ "delete_draft_response_status_code": nil,
70
+ "delete_draft_response_status": nil,
71
+ "security_classifications": {}
72
+ },
73
+ "event_id": "initiateCase"
74
+ }
75
+ JSON.generate(j)
76
+ end
77
+
78
+ def case_created_response(id, uid, jid, ctid)
79
+ j = case_hash(ctid, id, jid)
80
+ JSON.generate(j)
81
+ end
82
+
83
+ def case_hash(ctid, id, jid)
84
+ {
85
+ "id": id,
86
+ "jurisdiction": jid,
87
+ "state": "1_Submitted",
88
+ "case_type_id": ctid,
89
+ "created_date": "2019-07-01T09:37:37.936",
90
+ "last_modified": "2019-07-01T09:37:37.936",
91
+ "security_classification": "PUBLIC",
92
+ "case_data": ::EtFakeCcd::DataStoreService.find_case_data_by_id(id, jid: jid, ctid: ctid)['data'],
93
+ "data_classification": {},
94
+ "after_submit_callback_response": nil,
95
+ "callback_response_status_code": nil,
96
+ "callback_response_status": nil,
97
+ "delete_draft_response_status_code": nil,
98
+ "delete_draft_response_status": nil,
99
+ "security_classifications": {}
100
+ }
101
+ end
102
+
103
+ def cases_response(list, uid, jid, ctid)
104
+ j = list.keys.map do |id|
105
+ case_hash(ctid, id, jid)
106
+ end
107
+ JSON.generate(j)
108
+ end
109
+
110
+ def forbidden_error_for(r)
111
+ j = {"timestamp":"2019-07-01T07:46:35.405+0000","status":403,"error":"Forbidden","message":"Access Denied","path": r.path}
112
+ JSON.generate(j)
113
+ end
114
+
115
+ def render_error_for(command, request)
116
+ j = {
117
+ "exception": "uk.gov.hmcts.ccd.endpoint.exceptions.CaseValidationException",
118
+ "timestamp": "2019-07-01T16:02:28.045",
119
+ "status": 422,
120
+ "error": "Unprocessable Entity",
121
+ "message": "Case data validation failed",
122
+ "path": request.path,
123
+ "details": {
124
+ "field_errors": command.errors.details[:data].map {|e| e[:field_error]}
125
+ },
126
+ "callbackErrors": nil,
127
+ "callbackWarnings": nil
128
+ }
129
+
130
+ JSON.generate(j)
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,43 @@
1
+ require 'roda'
2
+ require 'json'
3
+ require 'et_fake_ccd/commands'
4
+ require 'et_fake_ccd/auth_service'
5
+ module EtFakeCcd
6
+ module Service
7
+ class SidamApp < Roda
8
+ plugin :request_headers
9
+ plugin :halt
10
+ route do |r|
11
+ r.is "loginUser" do
12
+ r.post do
13
+ command = ::EtFakeCcd::Command::LoginUserCommand.from_json(r.params)
14
+ if command.valid?
15
+ logged_in_result
16
+ else
17
+ r.halt 401, render_error_for(command)
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def logged_in_result
26
+ j = {
27
+ "access_token": ::EtFakeCcd::AuthService.generate_user_token,
28
+ "scope": "acr openid profile roles authorities",
29
+ "id_token": "eyJ0eXAiOiJKV1QiLCJraWQiOiJLQ3hCZGVoc0hVRjY5NzhTaXp2SVNFeGNYMEU9IiwiYWxnIjoiUlMyNTYifQ.eyJhdF9oYXNoIjoiWkFUeXNZVzE3UHk3a2ZKenp3dEhkdyIsInN1YiI6ImVyaWMuY2NkY29vcGVyQGdtYWlsLmNvbSIsImF1ZGl0VHJhY2tpbmdJZCI6Ijg0YjM0YzI2LTk4ZDktNGIxMS04MGIyLWRhOTAwOWM0MDM0MC0yMjE3MzM4Iiwicm9sZXMiOlsiY2FzZXdvcmtlci1lbXBsb3ltZW50LXRyaWJ1bmFsLW1hbmNoZXN0ZXItY2FzZXN1cGVydmlzb3IiLCJjYXNld29ya2VyLWVtcGxveW1lbnQtdHJpYnVuYWwtZ2xhc2dvdy1jYXNlb2ZmaWNlciIsImNhc2V3b3JrZXItZW1wbG95bWVudC10cmlidW5hbC1nbGFzZ293IiwiY2FzZXdvcmtlci1lbXBsb3ltZW50IiwiY2FzZXdvcmtlciIsImNhc2V3b3JrZXItcHVibGljbGF3LWxvY2FsQXV0aG9yaXR5IiwiY2FzZXdvcmtlci1lbXBsb3ltZW50LXRyaWJ1bmFsLW1hbmNoZXN0ZXIiLCJjYXNld29ya2VyLXB1YmxpY2xhdyIsImNhc2V3b3JrZXItZW1wbG95bWVudC10cmlidW5hbC1nbGFzZ293LWNhc2VzdXBlcnZpc29yIiwiY2FzZXdvcmtlci1lbXBsb3ltZW50LXRyaWJ1bmFsLW1hbmNoZXN0ZXItY2FzZW9mZmljZXIiXSwiaXNzIjoiaHR0cHM6Ly9mb3JnZXJvY2stYW0uc2VydmljZS5jb3JlLWNvbXB1dGUtaWRhbS1kZW1vLmludGVybmFsOjg0NDMvb3BlbmFtL29hdXRoMi9obWN0cyIsInRva2VuTmFtZSI6ImlkX3Rva2VuIiwiZ2l2ZW5fbmFtZSI6IkVyaWMiLCJhdWQiOiJobWN0cyIsImF6cCI6ImhtY3RzIiwiYXV0aF90aW1lIjoxNTYxNzM0NDY0LCJuYW1lIjoiRXJpYyBDQ0RfQ29vcGVyIiwicmVhbG0iOiIvaG1jdHMiLCJleHAiOjE1NjE3MzgwNjQsInRva2VuVHlwZSI6IkpXVFRva2VuIiwiZmFtaWx5X25hbWUiOiJDQ0RfQ29vcGVyIiwiaWF0IjoxNTYxNzM0NDY0fQ.Fh7E9DZiwXIyCAbapRG-TMcfp2HkmcYaLDms9g5_VhJvTtA3VnAykPStNN4ctC64SG2Kv6xJ5o_ivJlVxR5UqEdap-cD77JiRi0wMAOLfmB16n65i0XJkyVO4J5tw0odSS7nKOpZJ0-fW6lQh4qLhYjShUNDxT5iobmRC7TA195wNmDCG0K4oMcqbtT6S-TUGBbsVxdfOsB9kXxMYhCAfOJfgzFsDv_cs7PLY1y89GEdIT3o5SWD_f14U7ksp8Xkmv_mkI_Cl4AlqdMcU4uxjIoF37q5vcJUki7I7okbZJ93ePe99_eW0nxoCGk2qLX_RKID1ock9lSmThHQSXgxnw",
30
+ "token_type": "Bearer",
31
+ "expires_in": "28799",
32
+ "api_auth_token": "eyJtb25rZXkiOiJkWjFoVTFXb1RPVldZLTUydHRtN1A0OVB4ZTAuKkFBSlRTUUFDTURFQUFsTkxBQnh0THpRMVFsb3JRV1F3TVZZeVVqaE1iVTUxVTNaNFJYVlhaMnM5QUFKVE1RQUEqIiwicmFiYml0Ijoic2Vzc2lvbi1qd3Q9ZXlKMGVYQWlPaUpLVjFRaUxDSmpkSGtpT2lKS1YxUWlMQ0poYkdjaU9pSklVekkxTmlKOS5aWGxLTUdWWVFXbFBhVXBMVmpGUmFVeERTbXhpYlUxcFQybEtRazFVU1RSUk1FcEVURlZvVkUxcVZUSkphWGRwV1ZkNGJrbHFiMmxWYkU1Q1RWWTRNVWx1TUM1elF6VnFSakJFTFd3MVYySktUMGh4Y1ZNM2NVNVhXbXBtYkdrNWRERmlhMjFKYnpWYWVGaFlZa28wYXpkNE5FMTJVMW8zZUdkME9VUjFSR1UzVVVzM2JERnRaa1U1VWpNNUxXUXROMFJrWVdOaFdHVmpVa3Q1T0dOSGJ6UlBYMlpSZHpGc1draHROMjVRWlVwTFdHTkZSMlJJUkZSdE5sZG9iRVJwY3pCdk16SnZhR1ZpWVhOaWJFSk5aRkptWWxkbmMwbFliVUprVEMxQ2NsRnlPV1pJU1RGUFlVaHRlamxUU0c1VVZtdERVR2xvVjFVMGMzbHpSalI2WW5Fd1dUUldRV1U0TTJsak9WSktkMTlITFhKM05TMVdZME14UTB3d2FtdzNWbUZVT1ZOVGRtSm9iWGRsVVhBNGFUbFNTbkpqVm5CQlQzZFJZMHBpU0RobE4wNHdUbFpoY0dobFF6bFRVRTFEVWtNMlptZG5ZMlUzVHpabVZVSnhkemRDVEZSWFlURnhlV0Z5WmtwRGVIRjRaRlZZZUVRNFRXczVXWGhvZEVKRVZGUk1OMXBDUkV0RlN6Qm9TbTFGUlU5VldsSnhPVXh2TlhjdWF6WkRjblJsYmpJNFRtSkJRbUZQUm1keVVHUnNaeTVDVVZwSU1teEZYMFUwVWs5TlMwWnlUSFE1VURaUVpGaDZXRGRqVVhrMU5VaFROazV1Y2tOM1ZsbDNhak5RTUZweVpsVnhjRGhzTTA0dE1FdFZiVE5CZVV0TFQxZExkMGN0VFd4RE9XZGhabTVJVTJ4VE9VUnJkRmRDUkhNM2IyZE5SWG8zVjBKSGN6TlRTVkZuV0Y5c1IySjNSM001TmpObmFXWkVRazFZZHpaRGVWOXBXVmRNY25SYVFXZFlOSEJJTkhSd1dGbHFhbUZpTkhGcmNDMDFSREEzVms1ZmRVcFlNbkJrVDJNemFVWkRhRGxMVkZkUlZWbElXVlV4T1hjME5sSkdkWHBpUXpGWU1rTkZWVkJHUWxCSFRWSXlNRWRQY1U1eVZuVkJkbUpaUkVkWlJXWmlORzFQV0VwRE5ra3djM2xrVVZCNWFqSlBRemgwVUhRNGMxZFdPRWRKUVdWbFpEQndOVE5ETVU5UlFqRlBiSGhSUW5aeGRVVmZTVE5OUjNsdE1uSjBhalpTYWxCa1NHeGxkV2QyTmxSVloyRktjVmRNVUhveVdXNTZTSHBaWTNvdFJsZG9NVWszVW0weVVFUXphVmh3TUU5MGFtWmFjRTB6YTJOaFVFdDFWbkZUTm5sNVNtdHJialJ1TFc0eVZFbEJURTVEY21aNGJXUkVObDlFY2pWU2JUVTFWRlp6WW5OM2NGcFpkbmg0VEVZMlpYRlZTazR5ZUV4eGNURndRa1pvVjAxMWNVaDFVSFF6VEVOeVpESjNSVWxyWm5ocFQxTTBUREZKV1hwUmIyVktlbEJTTUZOUU1GQnpNM0JKU1dRMFdrbE5UbVZsUkdwbVl6Z3RXalZPVURsQlVVVnBUREJNVERsRU1tRm9iV2RIVHpCVlZEaEVlVlpVYURsYU1uWm9UMGhSYTJOcWFUWXdlblJUVEdJMmVHVmFlakp4ZVd4c1kzUm9Rbk5WWms0M09HTm5kamx2ZUdOUk1VSXlhSEV0TkZaUWJsTTNRVGN4ZEY5ZlNtSkVOakZvYzJSeVFWaGphMDkzUkhGYVQxaHNaRzB4U1RKRFVtaEtNVU5uYlhjMmJHdHhTM2hRWTNNNFdEVmtaMVZmWVcxNlpVaFFXWE5UUjI5a2VtbFlVamx1TjJGQ1oyWkhRMjVuZGxWeU1scFBUVGxFUm1WUFZGRmZTMk5KUWkxR1JqaE9YMkp5V0Y5UVFraEhSREJqT1VSS2Jub3lOM04xVWxWTGMzbzJlblJJWTJwUU5tdE5RM1V5TmpBeFlYWjZRbDh3WW5CeGRsZDZVM0oxY3pKTmRXdExaRGRPWmw5aVVsaFJaRkJuTFY5cWVXVndOWGhZTmpSblRqZDVjWEIyVG5KUE5sWXhjemR2VFcxQ1lXZ3phRlEzZFdkUFlsSjZhbXR0ZVZsWVgwVnBlVFJVT0VGMFRrTndZMU5FT0RBMmJIQXdaRVIyWjNVeVpGZFNNVTFuYUZsdk5TMXpYemxzWVdwNk5pMTFWVGQxU0dwWlJtZEllamhUT0VOd09VRTFiRTVhYzNGVFVXRm9kRzltY0VaMFJsWnRhR016U1RoME4ya3RkMWxZVEdoNVlVWk1ibkZ0UzFVMFl6Y3pWbUY1TWkxc1kxUkpTbU5tT1VGMVVHZDFiMFZFUWpKT2Ntc3hZa3RXTUdScFNVeFRPRFpPYVdKWE4ydE1ja2MxVURCb1JIcGllWEpxYW1RMGNUWlpaM2RuV25sdWIyWnRhazlSWm5GdVExbzVaV2xSWDJWR2J6Rm9YMmw1WDBaQmF6UXROVVZVYlVVMk5tOUNPVXMyUm5JelZtYzNSMDFHZUdKbWVYazRjVzVZU3pSdlIwUk9hVXRMTjNvMU1sTmlTbmRLTjJKSFExOHliRGRQUjJwUVNGaHNlbVJaV0VsSlowUldiMVZSZWs1WVZFdHFYMUV6WTBaaFIwUlhZM1Z5VEZFdVNUVlpVVTB6ZW5VeE5VZ3lVbkl3VmtjemNXbEpkdy5sOHBBbEd5WHhEUnQ3N0FZVy1YVHVlRUpMSVprUDV5OFo0MkI5RVotV240OyBQYXRoPS87IEh0dHBPbmx5In0="
33
+ }
34
+ JSON.generate(j)
35
+ end
36
+
37
+ def render_error_for(command)
38
+ "Its broke"
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,35 @@
1
+ require 'roda'
2
+ require 'json'
3
+ require 'et_fake_ccd/commands'
4
+ require 'et_fake_ccd/auth_service'
5
+ module EtFakeCcd
6
+ module Service
7
+ class UiApp < Roda
8
+ plugin :request_headers
9
+ plugin :halt
10
+ route do |r|
11
+ r.is "config" do
12
+ r.get do
13
+ config_result
14
+ end
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def config_result
21
+ j = {
22
+ "login_url": "http://localhost:8080/authentication-web/login",
23
+ "logout_url": "http://localhost:8080/api-gateway/logout",
24
+ "api_url": "http://localhost:8080/api-gateway/aggregated",
25
+ "case_data_url": "http://localhost:8080/api-gateway/data",
26
+ "document_management_url": "http://localhost:8080/api-gateway/documents",
27
+ "pagination_page_size": 25,
28
+ "oauth2_token_endpoint_url": "http://localhost:8080/api-gateway/oauth2",
29
+ "oauth2_client_id": "ccd_gateway"
30
+ }
31
+ JSON.generate(j)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,19 @@
1
+ require 'rotp'
2
+ module EtFakeCcd
3
+ module Validator
4
+ class OtpValidator < ActiveModel::EachValidator
5
+ def initialize(secret: ::EtFakeCcd.config.microservice_secret, **args)
6
+ self.otp = ROTP::TOTP.new(secret)
7
+ super
8
+ end
9
+
10
+ def validate_each(record, attribute, value)
11
+ record.errors.add :one_time_password, 'Invalid oneTimePassword' unless otp.verify(value, drift_behind: 15)
12
+ end
13
+
14
+ private
15
+
16
+ attr_accessor :otp
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module EtFakeCcd
2
+ VERSION = "0.1.4"
3
+ end
@@ -0,0 +1,27 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Sign in - HMCTS Access</title>
5
+ </head>
6
+
7
+ <body>
8
+ <form name="loginForm" class="form" novalidate autocomplete="off" method="post">
9
+ <input type="email" id="username" name="username" value="">
10
+ <input id="password" name="password" type="password">
11
+
12
+ <input type="hidden" name="continue" value="<%= oauth2_redirect_url %>">
13
+ <input type="hidden" name="upliftToken" value="">
14
+ <input type="hidden" name="response_type" value="code">
15
+ <input type="hidden" name="_csrf" value="WXIvDR4i-Hh1Pd5v5m0rthP0la1Sl0olVkXY">
16
+
17
+ <input type="hidden" name="redirect_uri" value="<%= oauth2_redirect_url %>">
18
+ <input type="hidden" name="client_id" value="<%= oauth2_client_id %>">
19
+ <input type="hidden" name="scope" value="">
20
+ <input type="hidden" name="state" value="">
21
+
22
+
23
+
24
+ <input class="button" type="submit" value="Sign in">
25
+ </form>
26
+ </body>
27
+ </html>
metadata ADDED
@@ -0,0 +1,202 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: et_fake_ccd
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ platform: ruby
6
+ authors:
7
+ - Gary Taylor
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-07-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: roda
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.21'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.21'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.20.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.20.3
41
+ - !ruby/object:Gem::Dependency
42
+ name: activemodel
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.2'
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 5.2.3
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '5.2'
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 5.2.3
61
+ - !ruby/object:Gem::Dependency
62
+ name: rotp
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '5.1'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '5.1'
75
+ - !ruby/object:Gem::Dependency
76
+ name: tilt
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '2.0'
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 2.0.9
85
+ type: :runtime
86
+ prerelease: false
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: '2.0'
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 2.0.9
95
+ - !ruby/object:Gem::Dependency
96
+ name: bundler
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '2.0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '2.0'
109
+ - !ruby/object:Gem::Dependency
110
+ name: rake
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '10.0'
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '10.0'
123
+ - !ruby/object:Gem::Dependency
124
+ name: rspec
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '3.0'
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: '3.0'
137
+ description: Fake CCD server for employment tribunals
138
+ email:
139
+ - gary.taylor@hmcts.net
140
+ executables:
141
+ - et_fake_ccd
142
+ extensions: []
143
+ extra_rdoc_files: []
144
+ files:
145
+ - ".gitignore"
146
+ - ".rspec"
147
+ - ".travis.yml"
148
+ - Gemfile
149
+ - Gemfile.lock
150
+ - LICENSE.txt
151
+ - README.md
152
+ - Rakefile
153
+ - bin/console
154
+ - bin/setup
155
+ - et_fake_ccd.gemspec
156
+ - exe/et_fake_ccd
157
+ - lib/et_fake_ccd.rb
158
+ - lib/et_fake_ccd/auth_service.rb
159
+ - lib/et_fake_ccd/cli.rb
160
+ - lib/et_fake_ccd/cli/root.rb
161
+ - lib/et_fake_ccd/command/create_case_command.rb
162
+ - lib/et_fake_ccd/command/lease_command.rb
163
+ - lib/et_fake_ccd/command/login_user_command.rb
164
+ - lib/et_fake_ccd/commands.rb
165
+ - lib/et_fake_ccd/config.rb
166
+ - lib/et_fake_ccd/data_store_service.rb
167
+ - lib/et_fake_ccd/root_app.rb
168
+ - lib/et_fake_ccd/service/api_gateway_web_app.rb
169
+ - lib/et_fake_ccd/service/auth_app.rb
170
+ - lib/et_fake_ccd/service/authentication_web_app.rb
171
+ - lib/et_fake_ccd/service/case_management_web_app.rb
172
+ - lib/et_fake_ccd/service/data_store_app.rb
173
+ - lib/et_fake_ccd/service/sidam_app.rb
174
+ - lib/et_fake_ccd/service/ui_app.rb
175
+ - lib/et_fake_ccd/validator/otp_validator.rb
176
+ - lib/et_fake_ccd/version.rb
177
+ - views/login.html.erb
178
+ homepage: https://github.com/hmcts/et-fake-ccd
179
+ licenses:
180
+ - MIT
181
+ metadata: {}
182
+ post_install_message:
183
+ rdoc_options: []
184
+ require_paths:
185
+ - lib
186
+ required_ruby_version: !ruby/object:Gem::Requirement
187
+ requirements:
188
+ - - ">="
189
+ - !ruby/object:Gem::Version
190
+ version: '0'
191
+ required_rubygems_version: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ requirements: []
197
+ rubyforge_project:
198
+ rubygems_version: 2.7.7
199
+ signing_key:
200
+ specification_version: 4
201
+ summary: Fake CCD server for employment tribunals
202
+ test_files: []