et_fake_ccd 0.1.4

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
+ 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: []