diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb new file mode 100644 index 0000000..800405f --- /dev/null +++ b/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb new file mode 100644 index 0000000..800405f --- /dev/null +++ b/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/controllers/.keep diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb new file mode 100644 index 0000000..800405f --- /dev/null +++ b/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/controllers/.keep diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000..1e7cf7b --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,13 @@ +require "test_helper" + +class UsersControllerTest < ActionDispatch::IntegrationTest + test "should get authenticate" do + get users_authenticate_url + assert_response :success + end + + test "should get presalt" do + get users_presalt_url + assert_response :success + end +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb new file mode 100644 index 0000000..800405f --- /dev/null +++ b/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/controllers/.keep diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000..1e7cf7b --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,13 @@ +require "test_helper" + +class UsersControllerTest < ActionDispatch::IntegrationTest + test "should get authenticate" do + get users_authenticate_url + assert_response :success + end + + test "should get presalt" do + get users_presalt_url + assert_response :success + end +end diff --git a/test/fixtures/autorities.yml b/test/fixtures/autorities.yml new file mode 100644 index 0000000..4d3ba82 --- /dev/null +++ b/test/fixtures/autorities.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + signature: MyString + +two: + name: MyString + signature: MyString diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb new file mode 100644 index 0000000..800405f --- /dev/null +++ b/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/controllers/.keep diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000..1e7cf7b --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,13 @@ +require "test_helper" + +class UsersControllerTest < ActionDispatch::IntegrationTest + test "should get authenticate" do + get users_authenticate_url + assert_response :success + end + + test "should get presalt" do + get users_presalt_url + assert_response :success + end +end diff --git a/test/fixtures/autorities.yml b/test/fixtures/autorities.yml new file mode 100644 index 0000000..4d3ba82 --- /dev/null +++ b/test/fixtures/autorities.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + signature: MyString + +two: + name: MyString + signature: MyString diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/fixtures/files/.keep diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb new file mode 100644 index 0000000..800405f --- /dev/null +++ b/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/controllers/.keep diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000..1e7cf7b --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,13 @@ +require "test_helper" + +class UsersControllerTest < ActionDispatch::IntegrationTest + test "should get authenticate" do + get users_authenticate_url + assert_response :success + end + + test "should get presalt" do + get users_presalt_url + assert_response :success + end +end diff --git a/test/fixtures/autorities.yml b/test/fixtures/autorities.yml new file mode 100644 index 0000000..4d3ba82 --- /dev/null +++ b/test/fixtures/autorities.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + signature: MyString + +two: + name: MyString + signature: MyString diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/fixtures/files/.keep diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 0000000..7793bdb --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,15 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString + +two: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb new file mode 100644 index 0000000..800405f --- /dev/null +++ b/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/controllers/.keep diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000..1e7cf7b --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,13 @@ +require "test_helper" + +class UsersControllerTest < ActionDispatch::IntegrationTest + test "should get authenticate" do + get users_authenticate_url + assert_response :success + end + + test "should get presalt" do + get users_presalt_url + assert_response :success + end +end diff --git a/test/fixtures/autorities.yml b/test/fixtures/autorities.yml new file mode 100644 index 0000000..4d3ba82 --- /dev/null +++ b/test/fixtures/autorities.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + signature: MyString + +two: + name: MyString + signature: MyString diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/fixtures/files/.keep diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 0000000..7793bdb --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,15 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString + +two: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString diff --git a/test/integration/.keep b/test/integration/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/integration/.keep diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb new file mode 100644 index 0000000..800405f --- /dev/null +++ b/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/controllers/.keep diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000..1e7cf7b --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,13 @@ +require "test_helper" + +class UsersControllerTest < ActionDispatch::IntegrationTest + test "should get authenticate" do + get users_authenticate_url + assert_response :success + end + + test "should get presalt" do + get users_presalt_url + assert_response :success + end +end diff --git a/test/fixtures/autorities.yml b/test/fixtures/autorities.yml new file mode 100644 index 0000000..4d3ba82 --- /dev/null +++ b/test/fixtures/autorities.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + signature: MyString + +two: + name: MyString + signature: MyString diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/fixtures/files/.keep diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 0000000..7793bdb --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,15 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString + +two: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString diff --git a/test/integration/.keep b/test/integration/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/integration/.keep diff --git a/test/mailers/.keep b/test/mailers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/mailers/.keep diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb new file mode 100644 index 0000000..800405f --- /dev/null +++ b/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/controllers/.keep diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000..1e7cf7b --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,13 @@ +require "test_helper" + +class UsersControllerTest < ActionDispatch::IntegrationTest + test "should get authenticate" do + get users_authenticate_url + assert_response :success + end + + test "should get presalt" do + get users_presalt_url + assert_response :success + end +end diff --git a/test/fixtures/autorities.yml b/test/fixtures/autorities.yml new file mode 100644 index 0000000..4d3ba82 --- /dev/null +++ b/test/fixtures/autorities.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + signature: MyString + +two: + name: MyString + signature: MyString diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/fixtures/files/.keep diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 0000000..7793bdb --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,15 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString + +two: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString diff --git a/test/integration/.keep b/test/integration/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/integration/.keep diff --git a/test/mailers/.keep b/test/mailers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/mailers/.keep diff --git a/test/models/.keep b/test/models/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/models/.keep diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb new file mode 100644 index 0000000..800405f --- /dev/null +++ b/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/controllers/.keep diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000..1e7cf7b --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,13 @@ +require "test_helper" + +class UsersControllerTest < ActionDispatch::IntegrationTest + test "should get authenticate" do + get users_authenticate_url + assert_response :success + end + + test "should get presalt" do + get users_presalt_url + assert_response :success + end +end diff --git a/test/fixtures/autorities.yml b/test/fixtures/autorities.yml new file mode 100644 index 0000000..4d3ba82 --- /dev/null +++ b/test/fixtures/autorities.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + signature: MyString + +two: + name: MyString + signature: MyString diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/fixtures/files/.keep diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 0000000..7793bdb --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,15 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString + +two: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString diff --git a/test/integration/.keep b/test/integration/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/integration/.keep diff --git a/test/mailers/.keep b/test/mailers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/mailers/.keep diff --git a/test/models/.keep b/test/models/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/models/.keep diff --git a/test/models/autority_test.rb b/test/models/autority_test.rb new file mode 100644 index 0000000..ed2c149 --- /dev/null +++ b/test/models/autority_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class AutorityTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb new file mode 100644 index 0000000..800405f --- /dev/null +++ b/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/controllers/.keep diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000..1e7cf7b --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,13 @@ +require "test_helper" + +class UsersControllerTest < ActionDispatch::IntegrationTest + test "should get authenticate" do + get users_authenticate_url + assert_response :success + end + + test "should get presalt" do + get users_presalt_url + assert_response :success + end +end diff --git a/test/fixtures/autorities.yml b/test/fixtures/autorities.yml new file mode 100644 index 0000000..4d3ba82 --- /dev/null +++ b/test/fixtures/autorities.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + signature: MyString + +two: + name: MyString + signature: MyString diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/fixtures/files/.keep diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 0000000..7793bdb --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,15 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString + +two: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString diff --git a/test/integration/.keep b/test/integration/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/integration/.keep diff --git a/test/mailers/.keep b/test/mailers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/mailers/.keep diff --git a/test/models/.keep b/test/models/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/models/.keep diff --git a/test/models/autority_test.rb b/test/models/autority_test.rb new file mode 100644 index 0000000..ed2c149 --- /dev/null +++ b/test/models/autority_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class AutorityTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/user_test.rb b/test/models/user_test.rb new file mode 100644 index 0000000..5c07f49 --- /dev/null +++ b/test/models/user_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class UserTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb new file mode 100644 index 0000000..800405f --- /dev/null +++ b/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/controllers/.keep diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000..1e7cf7b --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,13 @@ +require "test_helper" + +class UsersControllerTest < ActionDispatch::IntegrationTest + test "should get authenticate" do + get users_authenticate_url + assert_response :success + end + + test "should get presalt" do + get users_presalt_url + assert_response :success + end +end diff --git a/test/fixtures/autorities.yml b/test/fixtures/autorities.yml new file mode 100644 index 0000000..4d3ba82 --- /dev/null +++ b/test/fixtures/autorities.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + signature: MyString + +two: + name: MyString + signature: MyString diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/fixtures/files/.keep diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 0000000..7793bdb --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,15 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString + +two: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString diff --git a/test/integration/.keep b/test/integration/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/integration/.keep diff --git a/test/mailers/.keep b/test/mailers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/mailers/.keep diff --git a/test/models/.keep b/test/models/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/models/.keep diff --git a/test/models/autority_test.rb b/test/models/autority_test.rb new file mode 100644 index 0000000..ed2c149 --- /dev/null +++ b/test/models/autority_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class AutorityTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/user_test.rb b/test/models/user_test.rb new file mode 100644 index 0000000..5c07f49 --- /dev/null +++ b/test/models/user_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class UserTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..004f5a6 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,8 @@ +ENV["RAILS_ENV"] ||= "test" +require_relative "../config/environment" +require "rails/test_help" + +class ActiveSupport::TestCase + parallelize(workers: :number_of_processors) + fixtures :all +end diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb new file mode 100644 index 0000000..800405f --- /dev/null +++ b/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/controllers/.keep diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000..1e7cf7b --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,13 @@ +require "test_helper" + +class UsersControllerTest < ActionDispatch::IntegrationTest + test "should get authenticate" do + get users_authenticate_url + assert_response :success + end + + test "should get presalt" do + get users_presalt_url + assert_response :success + end +end diff --git a/test/fixtures/autorities.yml b/test/fixtures/autorities.yml new file mode 100644 index 0000000..4d3ba82 --- /dev/null +++ b/test/fixtures/autorities.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + signature: MyString + +two: + name: MyString + signature: MyString diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/fixtures/files/.keep diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 0000000..7793bdb --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,15 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString + +two: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString diff --git a/test/integration/.keep b/test/integration/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/integration/.keep diff --git a/test/mailers/.keep b/test/mailers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/mailers/.keep diff --git a/test/models/.keep b/test/models/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/models/.keep diff --git a/test/models/autority_test.rb b/test/models/autority_test.rb new file mode 100644 index 0000000..ed2c149 --- /dev/null +++ b/test/models/autority_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class AutorityTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/user_test.rb b/test/models/user_test.rb new file mode 100644 index 0000000..5c07f49 --- /dev/null +++ b/test/models/user_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class UserTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..004f5a6 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,8 @@ +ENV["RAILS_ENV"] ||= "test" +require_relative "../config/environment" +require "rails/test_help" + +class ActiveSupport::TestCase + parallelize(workers: :number_of_processors) + fixtures :all +end diff --git a/tmp/.keep b/tmp/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tmp/.keep diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb new file mode 100644 index 0000000..800405f --- /dev/null +++ b/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/controllers/.keep diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000..1e7cf7b --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,13 @@ +require "test_helper" + +class UsersControllerTest < ActionDispatch::IntegrationTest + test "should get authenticate" do + get users_authenticate_url + assert_response :success + end + + test "should get presalt" do + get users_presalt_url + assert_response :success + end +end diff --git a/test/fixtures/autorities.yml b/test/fixtures/autorities.yml new file mode 100644 index 0000000..4d3ba82 --- /dev/null +++ b/test/fixtures/autorities.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + signature: MyString + +two: + name: MyString + signature: MyString diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/fixtures/files/.keep diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 0000000..7793bdb --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,15 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString + +two: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString diff --git a/test/integration/.keep b/test/integration/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/integration/.keep diff --git a/test/mailers/.keep b/test/mailers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/mailers/.keep diff --git a/test/models/.keep b/test/models/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/models/.keep diff --git a/test/models/autority_test.rb b/test/models/autority_test.rb new file mode 100644 index 0000000..ed2c149 --- /dev/null +++ b/test/models/autority_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class AutorityTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/user_test.rb b/test/models/user_test.rb new file mode 100644 index 0000000..5c07f49 --- /dev/null +++ b/test/models/user_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class UserTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..004f5a6 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,8 @@ +ENV["RAILS_ENV"] ||= "test" +require_relative "../config/environment" +require "rails/test_help" + +class ActiveSupport::TestCase + parallelize(workers: :number_of_processors) + fixtures :all +end diff --git a/tmp/.keep b/tmp/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tmp/.keep diff --git a/tmp/pids/.keep b/tmp/pids/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tmp/pids/.keep diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb new file mode 100644 index 0000000..800405f --- /dev/null +++ b/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/controllers/.keep diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000..1e7cf7b --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,13 @@ +require "test_helper" + +class UsersControllerTest < ActionDispatch::IntegrationTest + test "should get authenticate" do + get users_authenticate_url + assert_response :success + end + + test "should get presalt" do + get users_presalt_url + assert_response :success + end +end diff --git a/test/fixtures/autorities.yml b/test/fixtures/autorities.yml new file mode 100644 index 0000000..4d3ba82 --- /dev/null +++ b/test/fixtures/autorities.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + signature: MyString + +two: + name: MyString + signature: MyString diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/fixtures/files/.keep diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 0000000..7793bdb --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,15 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString + +two: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString diff --git a/test/integration/.keep b/test/integration/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/integration/.keep diff --git a/test/mailers/.keep b/test/mailers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/mailers/.keep diff --git a/test/models/.keep b/test/models/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/models/.keep diff --git a/test/models/autority_test.rb b/test/models/autority_test.rb new file mode 100644 index 0000000..ed2c149 --- /dev/null +++ b/test/models/autority_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class AutorityTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/user_test.rb b/test/models/user_test.rb new file mode 100644 index 0000000..5c07f49 --- /dev/null +++ b/test/models/user_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class UserTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..004f5a6 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,8 @@ +ENV["RAILS_ENV"] ||= "test" +require_relative "../config/environment" +require "rails/test_help" + +class ActiveSupport::TestCase + parallelize(workers: :number_of_processors) + fixtures :all +end diff --git a/tmp/.keep b/tmp/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tmp/.keep diff --git a/tmp/pids/.keep b/tmp/pids/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tmp/pids/.keep diff --git a/tmp/storage/.keep b/tmp/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tmp/storage/.keep diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..31eeee0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# See https://git-scm.com/docs/gitattributes for more about git attribute files. + +# Mark the database schema as having been generated. +db/schema.rb linguist-generated + +# Mark any vendored files as having been vendored. +vendor/* linguist-vendored diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12439e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-* + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore pidfiles, but keep the directory. +/tmp/pids/* +!/tmp/pids/ +!/tmp/pids/.keep + +# Ignore uploaded files in development. +/storage/* +!/storage/.keep +/tmp/storage/* +!/tmp/storage/ +!/tmp/storage/.keep + +# Ignore master key for decrypting credentials and more. +/config/master.key diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..2eb2fe9 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +ruby-2.7.2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..ea05a23 --- /dev/null +++ b/Gemfile @@ -0,0 +1,23 @@ +source "https://rubygems.org" +git_source(:github) { |repo| "https://github.com/#{repo}.git" } + +ruby "2.7.2" + +gem "rails", "~> 7.0.2", ">= 7.0.2.3" +gem "sqlite3", "~> 1.4" +gem "puma", "~> 5.0" +gem "rack-cors", :require => 'rack/cors' +# gem "jbuilder" +# gem "redis", "~> 4.0" +# gem "kredis" +# gem "bcrypt", "~> 3.1.7" +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem "bootsnap", require: false +# gem "image_processing", "~> 1.2" +group :development, :test do + gem "debug", platforms: %i[ mri mingw x64_mingw ] +end + +group :development do + # gem "spring" +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..6090e83 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,177 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.2.3) + actionpack (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activesupport (= 7.0.2.3) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.2.3) + actionview (= 7.0.2.3) + activesupport (= 7.0.2.3) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.2.3) + actionpack (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.2.3) + activesupport (= 7.0.2.3) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.2.3) + activesupport (= 7.0.2.3) + globalid (>= 0.3.6) + activemodel (7.0.2.3) + activesupport (= 7.0.2.3) + activerecord (7.0.2.3) + activemodel (= 7.0.2.3) + activesupport (= 7.0.2.3) + activestorage (7.0.2.3) + actionpack (= 7.0.2.3) + activejob (= 7.0.2.3) + activerecord (= 7.0.2.3) + activesupport (= 7.0.2.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.2.3) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + bootsnap (1.11.1) + msgpack (~> 1.2) + builder (3.2.4) + concurrent-ruby (1.1.10) + crass (1.0.6) + debug (1.5.0) + irb (>= 1.3.6) + reline (>= 0.2.7) + digest (3.1.0) + erubi (1.10.0) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + io-console (0.5.11) + irb (1.4.1) + reline (>= 0.3.0) + loofah (2.16.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + method_source (1.0.0) + mini_mime (1.1.2) + minitest (5.15.0) + msgpack (1.4.5) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.3-x86_64-linux) + racc (~> 1.4) + puma (5.6.4) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.3) + rack-cors (1.1.1) + rack (>= 2.0.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (7.0.2.3) + actioncable (= 7.0.2.3) + actionmailbox (= 7.0.2.3) + actionmailer (= 7.0.2.3) + actionpack (= 7.0.2.3) + actiontext (= 7.0.2.3) + actionview (= 7.0.2.3) + activejob (= 7.0.2.3) + activemodel (= 7.0.2.3) + activerecord (= 7.0.2.3) + activestorage (= 7.0.2.3) + activesupport (= 7.0.2.3) + bundler (>= 1.15.0) + railties (= 7.0.2.3) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.2) + loofah (~> 2.3) + railties (7.0.2.3) + actionpack (= 7.0.2.3) + activesupport (= 7.0.2.3) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + reline (0.3.1) + io-console (~> 0.5) + sqlite3 (1.4.2) + strscan (3.0.1) + thor (1.2.1) + timeout (0.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.5.4) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + bootsnap + debug + puma (~> 5.0) + rack-cors + rails (~> 7.0.2, >= 7.0.2.3) + sqlite3 (~> 1.4) + tzinfo-data + +RUBY VERSION + ruby 2.7.2p137 + +BUNDLED WITH + 2.2.5 diff --git a/README.md b/README.md new file mode 100644 index 0000000..7db80e4 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..d1baef0 --- /dev/null +++ b/Rakefile @@ -0,0 +1,3 @@ +require_relative "config/application" + +Rails.application.load_tasks diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..ac36b70 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,72 @@ +class Api::UsersController < ActionController::API + def renderError + render :json => { "success" => false } + end + + def digParameter(name) + @data = params.dig(name) + renderError if !@data + return @data + end + + def getUsername + return digParameter('username') + end + + def getPasswordHash + return digParameter('passwordHash') + end + + def getUser + return nil if !@username = getUsername + @user = User.where(["username = ?", params[:username]]).first + renderError if !@user + return @user + end + + def isUserPasswordCorrect(user) + return if !@passwordHash = getPasswordHash + @correct = user.passwordHash == Digest::SHA256.hexdigest(@passwordHash + @user.secretSalt) + renderError if !@correct + return @correct + end + + def generateUserToken(user) + @token = UserToken.new(user) + return @token.toString + end + + def authenticate + return if !@user = getUser + return if !isUserPasswordCorrect(@user) + @result = { "success" => true, "token" => generateUserToken(@user) } + render :json => @result + end + + def presalt + return if !@user = getUser + @result = { "success" => true, "presalt" => @user.publicSalt } + render :json => @result + end + + def getToken + return digParameter('token') + end + + def checkToken + return if !@token = getToken + @jwt = JWT.new(@token) + @data = @token[0..@token.rindex('.')-1] + p @data + p @jwt.signature + Authority.all.each do |authority| + if @jwt.data['iss'] == authority.name && + @jwt.signature == OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + authority.signature, @data).tr('=', '') + render :json => { 'success' => true, 'valid' => true } + return + end + end + render :json => { 'success' => true, 'valid' => false } + end +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/controllers/concerns/.keep diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000..3c34c81 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout "mailer" +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..b63caeb --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + primary_abstract_class +end diff --git a/app/models/authority.rb b/app/models/authority.rb new file mode 100644 index 0000000..90a52b5 --- /dev/null +++ b/app/models/authority.rb @@ -0,0 +1,2 @@ +class Authority < ApplicationRecord +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/models/concerns/.keep diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..379658a --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ApplicationRecord +end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000..efc0377 --- /dev/null +++ b/bin/rails @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000..4fbf10b --- /dev/null +++ b/bin/rake @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby +require_relative "../config/boot" +require "rake" +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..ec47b79 --- /dev/null +++ b/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..5c59c6f --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require_relative "config/environment" + +run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..5243f4a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,14 @@ +require_relative "boot" +require "rails/all" + +Bundler.require(*Rails.groups) + +module WebsiteBackend + class Application < Rails::Application + config.load_defaults 7.0 + # config.time_zone = "Central Time (US & Canada)" + # config.eager_load_paths << Rails.root.join("extras") + config.api_only = true + config.autoload_paths << "#{Rails.root}/lib" + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..dd44191 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,4 @@ +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +require "bundler/setup" +require "bootsnap/setup" \ No newline at end of file diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000..68a94ce --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: website_backend_production diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc new file mode 100644 index 0000000..145ff81 --- /dev/null +++ b/config/credentials.yml.enc @@ -0,0 +1 @@ +amvkLidWhIjst4LXj1FYVS0Mc5ExMpwJ9K8hjM+uzcZQS7cEOwKl4qzlMJrCjUDjozr8m4Fu5yk/b4aIWK8Fcex+MGiKVrQQTjhRBhMa8QKZALRvll5EqqpwYH7CMKp2gdftTYW3R0bqYTsjrx3cQZOawnrlZ2CHjwTPf/Bh2aWTJ7HiJ85+WxqR5Ruvx58qTEGbtb/SU89sfU1Nr055+IYNVx8oZU8Xt7K/RE4ztQargfRG3m4ocvbdDFhxPzCGwRO4fO+PivTyZVUmy6YnO7+cltwrmrii38GhlaYM+oExuhXPG3Vwpgcihr4HuP0+5WsAQpi1meervf+gF7jpbY0ry8emz0IiTjgX8ciDKqdocK8MTBVmV/IWheGe/Kjmu3kI1rFgYifEAg33B6vXKikxeRwyzCZounxh--HFs/irQ30nlBTrUW--S24D1htKeLCJpw8ElRIG5Q== \ No newline at end of file diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..c52c94d --- /dev/null +++ b/config/database.yml @@ -0,0 +1,16 @@ +default: &default + adapter: sqlite3 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + timeout: 5000 + +development: + <<: *default + database: db/development.sqlite3 + +test: + <<: *default + database: db/test.sqlite3 + +production: + <<: *default + database: db/production.sqlite3 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..73a3979 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,3 @@ +require_relative "application" + +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..f5275d6 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,29 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + config.cache_classes = false + config.eager_load = false + config.consider_all_requests_local = true + config.server_timing = true + + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join("tmp/caching-dev.txt").exist? + config.cache_store = :memory_store + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + config.active_storage.service = :local + config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + config.active_support.deprecation = :log + config.active_support.disallowed_deprecation = :raise + config.active_support.disallowed_deprecation_warnings = [] + config.active_record.migration_error = :page_load + config.active_record.verbose_query_logs = true +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..e562ae0 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +require "active_support/core_ext/integer/time" + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = :info + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment). + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "website_backend_production" + + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Don't log any deprecations. + config.active_support.report_deprecations = false + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..6ea4d1e --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,60 @@ +require "active_support/core_ext/integer/time" + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = true + + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV["CI"].present? + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + "Cache-Control" => "public, max-age=#{1.hour.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + config.cache_store = :null_store + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true +end diff --git a/config/initializers/cors.rb b/config/initializers/cors.rb new file mode 100644 index 0000000..fb3a22c --- /dev/null +++ b/config/initializers/cors.rb @@ -0,0 +1,6 @@ +Rails.application.config.middleware.insert_before 0, Rack::Cors do + allow do + origins 'localhost' + resource '*', headers: :any, methods: [:post] + end +end \ No newline at end of file diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb new file mode 100644 index 0000000..adc6568 --- /dev/null +++ b/config/initializers/filter_parameter_logging.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..3860f65 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format. Inflections +# are locale specific, and you may define rules for as many different +# locales as you wish. All of these examples are active by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.plural /^(ox)$/i, "\\1en" +# inflect.singular /^(ox)en/i, "\\1" +# inflect.irregular "person", "people" +# inflect.uncountable %w( fish sheep ) +# end + +# These inflection rules are supported but not enabled by default: +# ActiveSupport::Inflector.inflections(:en) do |inflect| +# inflect.acronym "RESTful" +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..8ca56fc --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t "hello" +# +# In views, this is aliased to just `t`: +# +# <%= t("hello") %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# "true": "foo" +# +# To learn more, please read the Rails Internationalization guide +# available at https://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000..87d925f --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,15 @@ +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count + +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +port ENV.fetch("PORT") { 3000 } + +environment ENV.fetch("RAILS_ENV") { "development" } + +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } +# preload_app! +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..3fea316 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,6 @@ +Rails.application.routes.draw do + @root = 'api/' + post @root+'users/authenticate' + post @root+'users/presalt' + post @root+'users/checkToken' +end diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 0000000..4942ab6 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket-<%= Rails.env %> + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket-<%= Rails.env %> + +# Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name-<%= Rails.env %> + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20220403081640_create_users.rb b/db/migrate/20220403081640_create_users.rb new file mode 100644 index 0000000..babbc0b --- /dev/null +++ b/db/migrate/20220403081640_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[7.0] + def change + create_table :users do |t| + t.string :uuid + t.string :username + t.string :publicSalt + t.string :secretSalt + t.string :passwordHash + end + end +end diff --git a/db/migrate/20220403124644_create_authorities.rb b/db/migrate/20220403124644_create_authorities.rb new file mode 100644 index 0000000..9f20e15 --- /dev/null +++ b/db/migrate/20220403124644_create_authorities.rb @@ -0,0 +1,8 @@ +class CreateAuthorities < ActiveRecord::Migration[7.0] + def change + create_table :authorities do |t| + t.string :name + t.string :signature + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..b4ff532 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,27 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.0].define(version: 2022_04_03_124644) do + create_table "authorities", force: :cascade do |t| + t.string "name" + t.string "signature" + end + + create_table "users", force: :cascade do |t| + t.string "uuid" + t.string "username" + t.string "publicSalt" + t.string "secretSalt" + t.string "passwordHash" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..a6f9a95 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,18 @@ +def getHash(password, publicSalt, privateSalt) + return Digest::SHA256.hexdigest(Digest::SHA256.hexdigest(password + publicSalt) + privateSalt) +end + +def createUser(username, password) + @publicSalt = SecureRandom.hex(64) + @secretSalt = SecureRandom.hex(64) + User.create(uuid: SecureRandom.uuid, + username: username, + publicSalt: @publicSalt, + secretSalt: @secretSalt, + passwordHash: getHash(password, @publicSalt, @secretSalt)) +end + +createUser('admin', 'changeme') +createUser('lukas', 'test') +Authority.create(name:`hostname`.tr("\n", ''), signature: Rails.application.credentials.secret_key_base) +Authority.create(name: 'thirdParty', signature: 'thirdPartyKKey') diff --git a/lib/JWT.rb b/lib/JWT.rb new file mode 100644 index 0000000..86b41ef --- /dev/null +++ b/lib/JWT.rb @@ -0,0 +1,31 @@ +class JWT + attr_reader :data, :signature + + def initialize(data) + if data.class == String + @parts = data.split('.') + @header = JSON.parse Base64.urlsafe_decode64(@parts[0]) + @data = JSON.parse Base64.urlsafe_decode64(@parts[1]) + @signature = @parts[2] + p @signature + else + @header = defaultHeader + @data = data + end + end + + def defaultHeader + return { + 'alg' => 'HS256', + 'typ' => 'jwt' + } + end + + def toString + @string = Base64.urlsafe_encode64(@header.to_json).tr('=', '') + '.' + + Base64.urlsafe_encode64(@data.to_json) .tr('=', '') + @string = @string + '.' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), + Rails.application.credentials.secret_key_base, @string).tr('=', '') + return @string + end +end \ No newline at end of file diff --git a/lib/UserToken.rb b/lib/UserToken.rb new file mode 100644 index 0000000..0acb021 --- /dev/null +++ b/lib/UserToken.rb @@ -0,0 +1,10 @@ +class UserToken < JWT + def initialize(user) + super({ + 'iss': `hostname`.tr("\n", ''), + 'dat': Time.now.getutc, + 'typ': 'usr', + 'usr': user.username} + ) + end +end \ No newline at end of file diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/tasks/.keep diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/log/.keep diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..c19f78a --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/storage/.keep b/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/storage/.keep diff --git a/test/channels/application_cable/connection_test.rb b/test/channels/application_cable/connection_test.rb new file mode 100644 index 0000000..800405f --- /dev/null +++ b/test/channels/application_cable/connection_test.rb @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/controllers/.keep diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000..1e7cf7b --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,13 @@ +require "test_helper" + +class UsersControllerTest < ActionDispatch::IntegrationTest + test "should get authenticate" do + get users_authenticate_url + assert_response :success + end + + test "should get presalt" do + get users_presalt_url + assert_response :success + end +end diff --git a/test/fixtures/autorities.yml b/test/fixtures/autorities.yml new file mode 100644 index 0000000..4d3ba82 --- /dev/null +++ b/test/fixtures/autorities.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + signature: MyString + +two: + name: MyString + signature: MyString diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/fixtures/files/.keep diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 0000000..7793bdb --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,15 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString + +two: + uuid: MyString + username: MyString + publicSalt: MyString + secretSalt: MyString + passwordHash: MyString diff --git a/test/integration/.keep b/test/integration/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/integration/.keep diff --git a/test/mailers/.keep b/test/mailers/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/mailers/.keep diff --git a/test/models/.keep b/test/models/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/models/.keep diff --git a/test/models/autority_test.rb b/test/models/autority_test.rb new file mode 100644 index 0000000..ed2c149 --- /dev/null +++ b/test/models/autority_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class AutorityTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/user_test.rb b/test/models/user_test.rb new file mode 100644 index 0000000..5c07f49 --- /dev/null +++ b/test/models/user_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class UserTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..004f5a6 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,8 @@ +ENV["RAILS_ENV"] ||= "test" +require_relative "../config/environment" +require "rails/test_help" + +class ActiveSupport::TestCase + parallelize(workers: :number_of_processors) + fixtures :all +end diff --git a/tmp/.keep b/tmp/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tmp/.keep diff --git a/tmp/pids/.keep b/tmp/pids/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tmp/pids/.keep diff --git a/tmp/storage/.keep b/tmp/storage/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tmp/storage/.keep diff --git a/vendor/.keep b/vendor/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/vendor/.keep