Initialise Application & Run tests:
docker-compose up --build
This is to orchestrate web, db & test containers. The test container will run rspec.The endpoints are written in ruby on Sinatra framework. Rspec is used for testing.
Note: Ideally the SMTP credentials should not be hard-coded on the docker-compose file. This is done in this case to make it easier for the reviewer to test emails. The credentials are temporary.
*Caution: Possible bug in postman, when testing the verify_otp
endpoint, enter the OTP and hit save before sending the request. Sometimes old otp gets sent instead of a new one.
Endpoints
Additionally, postman collection arival.postman_collection.json
has been added for the reviewer's convenience when testing API endpoints.
Please test API endpoints in this sequence:
-
Register (check email for confirmation)
post '/register', { email: 'test@example.com', password: 'password' }.to_json, 'CONTENT_TYPE' => 'application/json'
-
Login
post '/login', { email: 'test@example.com', password: 'password' }.to_json, 'CONTENT_TYPE' => 'application/json'
-
Enable 2FA (pass user_id from login response)
put '/settings/enable_otp/1', {}.to_json, 'CONTENT_TYPE' => 'application/json' # user_id = 3
-
Login
post '/login', { email: 'test@example.com', password: 'password' }.to_json, 'CONTENT_TYPE' => 'application/json'
-
Verify OTP: Enter the OTP received on Email (pass user_id from login response)
post "/login/verify_otp/#{user.id}", { otp: '123456' }.to_json, 'CONTENT_TYPE' => 'application/json'
-
Disable 2FA (pass user_id from login response)
put '/settings/disable_otp/1', {}.to_json, 'CONTENT_TYPE' => 'application/json' # user_id = 3
-
Login to verify
post '/login', { email: 'test@example.com', password: 'password' }.to_json, 'CONTENT_TYPE' => 'application/json'
-
Change Password (pass user_id from login response)
put '/settings/change_password/1', { current_password: 'password', new_password: 'new_password' }.to_json, 'CONTENT_TYPE' => 'application/json'
Security
- Bcrypt is used for securely hashing and storing the password in the db.
- ROTP is used for generating time based one-time password. We are using a proven library to reduce the security risk that can possibly raise due to reinventing the wheel or writing a TOPT algorithm.
- Sinatra comes with built-in security features through Rack Protection. Rack Protection has been enabled to prevent common attacks.
- ActiveRecord's has_secure_password is used to securely hash and store the password in the db. This is due to time constraint and avoid security flaws.
Possible Improvements
- Use token-based authentication (e.g., JWT) to secure API endpoints. Authenticate and authorize users before allowing access to sensitive resources. This was skipped due to time constraints.
- Rate limiting could be implemented to circumvent Denial-of-Service attacks.
- Proper logging & instrumentation can be implemented for monitoring.
- Emails can be moved to a background job.
- Register endpoint can have token confirmation via email.
- Backup OTP code can be implemented.