How to test two-factor authentication with QR images - ruby-on-rails

I'm currently in the process of adding two-factor authentication to a rails app. I added a process that lets users enable two-factor authentication, by using a QR code to verify themselves. I'm using this gem: https://github.com/Houdini/two_factor_authentication, which lets you generate a provisioning uri that can be turned into a QR code. The user can then scan this with apps like Authy or Google authenticator, to get a one-time password.
I'm now at the point where I need to write tests for this, and I therefore need to be able to automate the process of getting security codes from the provisioning uri, without the need to scan it with an app.
So my question is: Is it possible to get the secret key, that you would get by scanning the QR code, programmatically and if so, how?
The app is based on Ruby on rails 5.2.

When you want to test a feature from a specific gem, in the most cases you can find some clues in the original repo. Popular gems usually are well tested. Take a look here https://github.com/Houdini/two_factor_authentication/blob/master/spec/lib/two_factor_authentication/models/two_factor_authenticatable_spec.rb#L182

You have two options:
Find a way to read the QR in Ruby. This would most resemble what the user has to do, but may be hard (I don’t know — I've never done it).
Generate the 6-digit code (the "TOTP code") yourself. This feels a little more hacky (and dives into some implementation details, I suppose) but is easier to do than option 1.
For option 2, you can use the rotp gem (which Houdini uses itself) and the secret key you generate through Houdini.
secret_key = user.generate_totp_secret
# then...
totp = ROTP::TOTP.new(secret_key)
totp.now # --> the 6-digit code
(You can see how Houdini uses the rotp gem here.)

Related

Using an API key in Rails App

I just got an API key for a database I wish to access and want to start building my Rails app. However I dont know where to begin with the API key. Specifically I want to use the brewerydb data and I am building an app where users can find the closest brewery to their location. Can anyone tell me how to get started? I am new to Rails and have never used an API before. I don't know where to begin. What file should I put it in, etc... I know I should probably update the GEMFILE, where else?
Thanks!
Check the documentation for the API. That's all I can say. (well... not really: )
Most API's rely on REST or SOAP, which is basically making HTTP request to certain URI's. An example may be
http://api.somewebsite.com/beers.json
Which would return, for instance, a JSON array of certain beers and their properties.
Furthermore, more often than not, you can test API's (that do not require certain HTTP headers for authentication, which makes it harder) by manually constructing the URI's and opening them in your browser. This way, you can verify that your request is okay before you try it in your Rails application an cannot figure out why it's not working.
You should use the 'figaro' gem https://github.com/laserlemon/figaro
It creates a "application.yml" file in which you can add your API key.

Stripe "Invalid API Key Provided"

I have followed Stripe's Rails tutorial (https://stripe.com/docs/checkout/guides/rails) exactly (copy and pasted code), but when I run rails
PUBLISHABLE_KEY=pk_foo SECRET_KEY=sk_bar rails s
and go to localhost:3000/charges/new and fill out the fields with the test card data (card number "4242 4242 4242 4242"), but I get an
Invalid API Key provided: ***********_***
Any ideas why this is happening?
You need to plug in your publishable key and secret key; pk_foo and sk_bar are placeholders. (Unlike the API docs, the Checkout tutorial doesn't use information from your account.)
You can get them from the API Keys tab of Your Account.
i.e. for a secret key of Sk123456 and a publishable key of pk_987654, you'd issue:
PUBLISHABLE_KEY=pk_987654 SECRET_KEY=Sk123456 rails s
If that still doesn't work there are a couple things to check:
Are both keys from the same environment (test or live)? Occasionally people mix the two together.
If you load a Rails console instead of a Rails server, can you access those environment variables with ENV['PUBLISHABLE_KEY'] and ENV['SECRET_KEY']?
If you're using multiple APIs, it's possible you have some kind of collision occurring; you might try adjusting the command-line and the code to STRIPE_PUBLISHABLE_KEY and STRIPE_SECRET_KEY.
another thing you might check is that the API keys you are using are actually the right ones. What happened to me is that I was scanning the keys in Stripe Dashboard and the ones in my .env file, and made a snap judgement that they were the same based on how they started and ended. They both looked like this, with every character identical, except for the 3rd character:
sk_test_******************************D6D
For whatever reason, when Stripe rolls a new key, they keep it almost the same.
In short, don't trust your eyes, and make sure the keys are actually the same.

Is it correct to store vcr cassettes in repository?

I develop a Ruby interface for one REST api. I use rspec and vcr for testing.
All tests use credentials of account, specially created for it.
I can't decide: is it correct to store cached responses of my tests(vcr cassettes) in
repository, or allow users and subscribers to write their own cassettes?
By the name of the Emperor! Let the Holy War begins!
VCR's cassettes play as the fixture of your tests. You do need to commit them into repository otherwise your tests won't run correctly in others' machine, or only correct there with heavy external dependency which is a violation of testing principle.
Of course you need to hide your credentials from public or team while keeping the above.
The solution is filter_senstive_data settings and Figaro gem.
At first, This answer from Myron in a similar question can solve your problem largely.
To setup VCR
VCR.configure do |c|
c.filter_sensitive_data("<SOMESITE_PASSWORD>") do
ENV['SOMESITE_PASSWORD']
end
end
The above block of code copied from Myron's answer because I want to add more later
For more about this setting, check the doc https://relishapp.com/vcr/vcr/v/2-5-0/docs/configuration/filter-sensitive-data
Now, for ENV['SOMESITE_PASSWORD'], it can be real credential by using Figaro gem.
Installation of Figaro will create a file config/application.yml and add it to .gitignore. So, you can just input your credential username and password there without risking leaking it to public.
As long as you aren't including any sensitive information in the requests then I see no reason why you can't commit them.
But as long as it will work fine after first test seeding the cassettes there isn't too much at stake either way.
Personally I like the idea of being checked against historical requests in case I have to diagnose some obscure machine-specific error changing my request formats. (IE some encoding bug where things are being escaped incorrectly due to a dynamically loaded library).

PayPal API With ActiveMerchant (Legacy Code)

I've inherited some legacy Rails code (2.1.3) and there appears to be a public_cert as well as a signature. I thought PayPal used one or the other, but my configuration seems to have both:
config.app_config.pay_pal.merge!(
:password=>"WHATEVER",
:public_key=>"-----BEGIN CERTIFICATE-----\nMIICmTCCAgKgAwIBAgIDEcmhMA0GCSqGSIb3DQEBBQUAMIGZMQswCQYDVQQGEwJV\nUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2UxFTATBgNV\nBAoTCHANGEDSTUFFqe0RzCDhQmVhgtNWZxeqzjVbVrCx80jF1\nWi/+ksJQLPViFj9+F4WS5i4MjMeCIwIDAQABow0wCzAJBgNVHRMEAjAAMA0GCSqG\nSIb3DQEBBQUAA4GBAMwavx4Eh2JCOCOc/WvL7zdRL07So48mQ9aJr4Bxdgib+/z2\nkqX0ZPJv9T6NQ1h9lcwohIuaJMXtLAysJMjvKcvPdzcHqB6Xv+OGpi2REJjUdB39\n9amutkxQVhKBfK3hCP4+8UlM1yzxejyK8SVWSJCbc5zvJFoLV4SZcbNevtw9\n-----END CERTIFICATE-----\n",
:business=>"me#site.com",
:business_id=>"4WSDFSFSDF",
:login=>"me_api1.site.com",
:cert_id=>"AAAA",
:private_key=>"-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQDm5fXKcp6ht6+Be4Y7VOaNvEPZwVqRt0CHANGEDMORESTUFFKTF7Mozcg12qiq1VDqFYwQF\n8gteGGLFy3GKPWlpqtJzAI4xfpI07d2ivgfXkk4Q74np+P8udulM0bEA+WAoGO6e\nHZ7g0/EbutA0+H5TTSp3gUYa5xcUhSrMiYN/r6HK+aeKnNECQQD8D/oBjEsZwsAB\n2KxDLZfEcrmFiLxjqQSBKPtMJP0Lrhl7OyB2v1o3QDA5+QdbDFbRxA1RNQfw+ZXo\nPuP49DRpAkEA6oFYlNnGvNWlHxDmVob5q88HEgP/ZEWFJXzZcSsAkJNrbdyPCdSj\nxN2M0duJlegJlfsr6l9OyBeFcSXnrVSAqwJBAO7BP2FJ/zUGeJMHJpx3SkOFG9+1\nliScSy0AoZANlTcEERTd+7EfLZgaD9RJ40LF3FLTbn3WSpBiCTG0qIH+5skCQF4K\n5SU8eJC99OwScOz+UB3wdltpMwBZSN4RxXm2zxErrYdvTgWZOtv2JUT7j5+IYF+/\nTIs/EW74z9DibJh8LOUCQEsMclIUTorjVVtAgI5LiSwenDSCgf9Ra0r3CoL3dAGz\n1RskSziPqfQyA2QDFfSPkmycgxPlZvP0G8fwuBs6sjI=\n-----END RSA PRIVATE KEY-----\n",
:signature=>"AwhNvKUCHANGEDSTUFF9xveB4"
)
I'm using PayPal Payments Standard I believe with Rails ActiveMerchant.
Any help would be greatly appreciated
PayPal only allows you to use one or the other. It may have been that the previous person generated the cert or signature and added it to the code, only to switch over to the other method at a later date and never removed it from the code. If it's currently working and processing payments on the PayPal account, you could log into the PayPal account and see which one is currently active on the account. You are only going to see one or the other. Which ever one you are seeing, means the other one would not be being used. If it's not showing, it would not be valid anymore.
Another option, would be you could walk thru the code and see where the API call is being made, and check which one it is sending across to PayPal.

What is the standard way to handle twitter API keys in GPL'd desktop applications?

While developing an desktop application that needs to access twitter API , one must somehow pass the API key (application specific consumer key and consumer secret ) for the application to the user. Twitter's API TOS states that the application's API key cannot be publicly available and if that happens, they reset it. When that application is under GPL , meaning the developer needs to provide the source code to the user, how that user would be able to obtain the API key without it being publicly available ? Is there a standard way to handle this issue ?
Thanks.
Edit:
To clarify the situation, I was storing them in plain text in my code for cree.py so far as a conscious decision. But yesterday Twitter support team contacted me that they have reseted my key and their reasoning was the following :
C. You should not solicit another developer's consumer keys or consumer secrets especially if they will be stored or used for actions outside of that developer's control. Keys and secrets that are compromised will be reset by Twitter. For example, online services that ask for these values in order to provide a "tweet-branding" service are not allowed.
https://dev.twitter.com/terms/api-terms
If an application's keys are posted publicly, it allows for external parties to hijack the application's API access. This presents an enormous abuse risk, and as such we've reset your API keys. Please take care to ensure that these keys are not posted publicly again.
Thanks,
Twitter API Policy
Well, TTYtter evidently uses the honour system:
# yes, this is plaintext. obfuscation would be ludicrously easy to crack,
# and there is no way to hide them effectively or fully in a Perl script.
# so be a good neighbour and leave this the fark alone, okay? stealing
# credentials is mean and inconvenient to users. this is blessed by
# arrangement with Twitter. don't be a d*ck. thanks for your cooperation.
$oauthkey = (!length($oauthkey) || $oauthkey eq 'X') ?
"XXXXXXXXXXXXXXXXXXXXX" : $oauthkey;
$oauthsecret = (!length($oauthsecret) || $oauthsecret eq 'X') ?
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" : $oauthsecret;
(I have replaced the actual keys with Xs, to make it a little less likely that anyone will go to the trouble to abuse them, but rest assured that they are present in full in the actual source!)
Also, I don't see anything in the Rules of the Road actually requiring you to keep these things secret: the closest thing I see is the statement "Keys and secrets that are compromised will be reset by Twitter."; they never actually say what "compromised" means, though.
I might be dense here, but why don't you store them in a configuration file, the Windows registry etc and get them from there? Then distribute the application without the file, and you're done.
Maybe another solution would be to use a server, the server interacts with the twitter api, and the you request information to your server with your desktop application
Like that, the API key is only stored on the server, and not any user can get it.

Resources