Active model OTP not generating new secret key after 30 seconds sleep - ruby-on-rails

I am trying implement active_model_otp on a sample rails application.
My user model has name and email columns. After following the necessary steps from the documentation I first created a user as follows on rails console:
User.create(name: "Abc", email: "example#email.com")
This created a record as follows:
<User id: 1, name: "Abc", email: "example#email.com", created_at: "2017-04-28 07:12:25", updated_at: "2017-04-28 07:12:25", otp_secret_key: "lol6rrtqppy46xfs">
Then I assigned:
user = User.last and
user.otp_secret_key gave the otp that was generated which is
=>"lol6rrtqppy46xfs"
Then I ran
sleep(2)
According to given documentation it supposed to generate a new otp after 2 seconds. But when I gave: user.otp_secret_key again in the console after 2 seconds it is returning the same old otp.
=>"lol6rrtqppy46xfs"
What am I missing ?

Twilio developer evangelist here.
The otp_secret_key is the string that is used to generate the actual OTP code that you send to the user. It is the secret that is shared to the user (via the QR code) and so it needs to match on both the user's auth app as well as your server.
The generated OTP should change every 30 seconds. As far as I can see it uses the default interval of the ROTP gem, which is 30 seconds.
The method to get the OTP is otp_code. So to check it's working, try:
user = User.last
puts user.otp_code
sleep(30)
puts user.otp_code
Let me know if that helps at all.

Related

How to debug RocketChat error-not-allowed (trying to invite and add/remove owners)

We're using RocketChat via a Docker image rocketchat/rocket.chat:0.68.4 and the Ruby rocketchat gem.
There's already some working functionality to update a channel's attributes:
# RocketChatService is a wrapper class for a RocketChat::Session object with authentication as admin
channels = RocketChatService.channels
channels.set_attr(name: id, topic: escape_nil(title)) if title_changed?
channels.set_attr(name: id, description: escape_nil(description)) if description_changed?
channels.set_attr(name: id, custom_fields: { project_id: project_id }) if project_id && project_id_was.nil?
But now we also need to add new users to a room, make them owner, or degrade previous owners. The following code works under certain circumstances (which I'm afraid are to complex to be presented here), but sometimes causes errors:
# idempotent
channels.invite(name: id, username: creator_id)
# TODO: already an owner
channels.add_owner(name: id, username: creator_id)
channels.remove_owner(name: id, username: creator_id_was)
The problem is that these error messages aren't very informative:
"exception"=>"Not allowed [error-not-allowed]"
There's no log file in RocketChat and there's nothing written to stdout when this happens. That brings me to my question: How can I debug an error message like the one above?

Can I use the Slack API to set the profile picture?

I am running a Slack team for a gaming community. My users all have avatars in the game and I am already using the Slack API to automatically set their Slack user name to their in-game name, so its easier for people to be recognized.
In addition I would also like to automatically set their profile picture in Slack with their avatar picture from the game. However I could not figure out a way to do it, so my question is can it be done and if yes, how?
My current starting point is the undocumented API method users.profile.set which allows me to set the profile of a user (see below for an example of a user profile). So far I've been able to modify:
first_name
last_name
title
phone
skype
The user profile also contains the URL to the profile picture, but I was so far not able to change it. I tried external URLs, and URLs of images already uploaded on Slack.
Here is a link to my documentation of the "undocumented" Slack API method users.profile.set with all options that I could figure out so far.
Any help would be hugely appreciated.
Update November 2017
In the meantime Slack has added a new API method called users.setPhoto for setting profile photos. However, this new method does not solve this question, because it only works for your own user (or more precisely the user you have an access token for, e.g. you not specify another user ID).
I am looking for a way to change the profile pictures of all users on my Slack team by a Slack app / bot.
Example of a user profile:
{
id: "U12345678",
team_id: "T12345678",
name: "erik.kalkoken",
deleted: false,
status: null,
color: "9f69e7",
real_name: "Erik Kalkoken",
tz: "America/Chicago",
tz_label: "Central Daylight Time",
tz_offset: 3600,
profile: {
avatar_hash: "XXX",
first_name: "Erik",
last_name: "Kalkoken",
title: "",
phone: "",
skype: "",
image_24: "https://avatars.slack-edge.com/2016-03-19/XXX_24.jpg",
image_32: "https://avatars.slack-edge.com/2016-03-19/XXX_32.jpg",
image_48: "https://avatars.slack-edge.com/2016-03-19/XXX_48.jpg",
image_72: "https://avatars.slack-edge.com/2016-03-19/XXX_72.jpg",
image_192: "https://avatars.slack-edge.com/2016-03-19/XXX_192.jpg",
image_512: "https://avatars.slack-edge.com/2016-03-19/XXX_512.jpg",
image_1024: "https://avatars.slack-edge.com/2016-03-19/XXX_512.jpg",
image_original: "https://avatars.slack-edge.com/2016-03-19/XXX_original.jpg",
real_name: "Erik Kalkoken",
real_name_normalized: "Erik Kalkoken",
email: "test#email.com"
},
is_admin: false,
is_owner: false,
is_primary_owner: false,
is_restricted: false,
is_ultra_restricted: false,
is_bot: false,
has_2fa: false
}
After messing around with it for a little, it's possible to use the undocumented users.setPhoto endpoint:
curl https://slack.com/api/users.setPhoto \
-F "token=<removed>" \
-F "image=#/path/to/image.jpg"
Unfortunately it will resize your avatar which removes the ability to upload animated gifs.
I don't think the profile picture API is available yet. I read a while back that it was on their TODO list.
I was able to get it to work using Jay Querie's method.
The two difference was I gave the full path and I put the image first.
So in my case:
curl https://slack.com/api/users.setPhoto -F "image=#C:\Users\name\Pictures\dojocat.jpg" -F "token=xxxx-123-123-123-123"
Originally when I was using gitbash to run the curl and it was searching for the image in the directory where my gitbash was installed / being executed. So if I put the dojocat.jpg next to my gitbash executable it would would have found it.

"The token is invalid" when trying to setup Paypal recurring payments with ActiveMerchant

I feel like a lot of the documentation on this is outdated, but this is what I have been trying so far:
I am using the ActiveMerchant::Billing::PaypalExpressGateway gateway.
First I setup the purchase and redirect the user to Paypal:
response = gateway.setup_purchase price,
return_url: <confirm url>,
cancel_return_url: <cancel url>,
items: [
{
name: 'My Item',
quantity: 1,
description: "My Item Description",
amount: price
}
]
redirect_to gateway.redirect_url_for(response.token)
This works, I can sign in as a sandboxed buyer and confirm the payment, which brings me back to <confirm url> from above. In the confirmation, I do:
response = gateway.recurring price, nil,
token: params[:token],
period: 'Year',
frequency: 1,
start_date: Time.now,
description: 'My Item Subscription'
When I do this, I receive an invalid token error from Paypal in the response variable. The token seems to be fine, it is present in the URL when I am brought back to the confirmation URL. I'm then taking it directly (params[:token]) and sending it back to Paypal.
Am I doing something completely wrong? Like I said, it seems like a lot of the documentation for this type of process is outdated (or maybe what I am trying is the stuff that is outdated...)
After looking through the source code for ActiveMerchant's Paypal express checkout gateway, I came to the conclusion that it's simply outdated when dealing with recurring payments. I switched to the paypal-recurring gem instead and everything worked fine.

Google Provisioning API no longer allowing restore(unsuspend) of user

Anybody else seeing this?
There appears to have been some changes to the Google provisioning api for multi-domains. I have long running code that could restore a suspended user that has stopped working. I use Python and 2.0.17 of the Python GData libraries and the UpdateUser method to do this. I have also noted that RetrieveUser in the same library is no longer returning the first and last names of suspended users. I have filed an issue at Google apps-api-issues, please star if you are seeing this.
http://code.google.com/a/google.com/p/apps-api-issues/issues/detail?id=3281
This is a simple example that will walk through the problem. Note that user_entry object returned from a RetrieveUser() on a suspended user will not have a property value for either first name or last name. The modified user_entry object is passed to UpdateUser() which does not allow the missing values for first and last names.
#!/usr/bin/python
import sys
import gdata.apps.multidomain.client
if len(sys.argv) < 4:
print "\nUsage:"
print sys.argv[0], "admin_email admin_password user_email\n"
sys.exit(0)
admin = sys.argv[1]
password = sys.argv[2]
email = sys.argv[3]
domain = ""
if '#' in admin:
admin_name,domain = admin.split('#', 1)
else:
print "Specify full email address of administrator.\n"
print "\nUsage:"
print sys.argv[0], "admin_email admin_password user_email\n"
sys.exit(0)
if '#' not in email:
print "Specify full email address of user.\n"
print "\nUsage:"
print sys.argv[0], "admin_email admin_password user_email\n"
sys.exit(0)
md_client = gdata.apps.multidomain.client.MultiDomainProvisioningClient(
domain=domain)
md_client.ClientLogin(email=admin, password=password, source='MDPROVISIONING')
print "Retrieve user: %s\n" %(email)
user_entry = md_client.RetrieveUser(email)
print user_entry
print ('\nRetrieve results: email: %s, suspended: %s,'
' first name: %s, last name: %s\n'
%(user_entry.email,user_entry.suspended,
user_entry.first_name,user_entry.last_name))
print "Update user (suspend): %s\n" %(email)
user_entry.suspended = 'true'
updated_user_entry = md_client.UpdateUser(email, user_entry)
print updated_user_entry
print ('\nSuspend results: email: %s, suspended: %s,'
' first name: %s, last name: %s\n'
%(updated_user_entry.email,updated_user_entry.suspended,
updated_user_entry.first_name,updated_user_entry.last_name))
print "Retrieve user: %s\n" %(email)
user_entry = md_client.RetrieveUser(email)
print user_entry
print ('\nRetrieve results: email: %s, suspended: %s,'
' first name: %s, last name: %s\n'
%(user_entry.email,user_entry.suspended,
user_entry.first_name,user_entry.last_name))
print "Update user (restore): %s\n" %(email)
user_entry.suspended = 'false'
updated_user_entry = md_client.UpdateUser(email, user_entry)
print updated_user_entry
print ('\nRestore results: email: %s, suspended: %s,'
' first name: %s, last name: %s\n'
%(updated_user_entry.email,updated_user_entry.suspended,
updated_user_entry.first_name,updated_user_entry.last_name))
Thanks user1803418, that explains why restoring a user works with GAM and not your code. The lack of firstName and lastName in the RetrieveUser API call is definitely an issue on Google's end that they'll need to fix. However, I'd describe the unsuspend issue as a client library deficiency that's excaberated by the firstName/lastName issue.
The API requires only attributes that are being updated be submitted in the update user API call. There's no need to specify the user's firstName, lastName and other object details. This means retrieving the user in order to perform the update simply makes the update process take longer, only one API call is really necessary.
GAM uses it's own implementation of the multidomain API calls which I wrote before the multidomain/client.py was released. GAM's implementation does not require that all user attributes be set in order to perform the update. You can see this by looking at:
http://code.google.com/p/google-apps-manager/source/browse/trunk/gdata/apps/multidomain/service.py#69
only the attributes that are set when calling UpdateUser() are sent to Google. You can see this for yourself by installing GAM and creating a file named debug.gam before unsuspending the user with the GAM command:
gam update user suspended off
the XML request to Google will be minimal, showing only a few fields including the suspended status of the user. firstName and lastName will not be included in the request.
So I think you have 3 options here:
1) wait for a fix from Google for the firstName/lastName issue. This should resolve the unsuspend issue also.
2) rewrite the multidomain/client.py UpdateUser() function so that it does not require all user attributes to be set in order to perform the update.
3) switch your code to use GAM's custom multidomain/service.py library since it supports updating only provided attributes for a user.
I hope that Google fixes the missing names soon.
Modifying UpdateUser in the multidomain client
(gdata.apps.multidomain.client) seems to keep things going:
def update_user(self, email, user_entry, **kwargs):
user_entry = gdata.apps.multidomain.data.UserEntry(
email=email,first_name=user_entry.first_name,
last_name=user_entry.last_name,password=user_entry.password,
change_password=user_entry.change_password_at_next_login,
suspended=user_entry.suspended, is_admin=user_entry.is_admin,
ip_whitelisted=user_entry.ip_whitelisted, quota=user_entry.quota)
return self.update(user_entry,
uri=self.MakeMultidomainUserProvisioningUri(email),
**kwargs)

Issues with extracting Facebook Omniauth Authentication uid on Rails 3.1

I'm trying to extract and save in my db, the uid of a Facebook user's Omniauth Authentication.
When I issue the command user.authentications, the resulting array is displayed:
[ < Authentication id: 3, user_id: 63, provider: "facebook", uid: "123456789", created_at: "2012-07-02 02:10:48", updated_at: "2012-07-02 02:10:48" > ]
But when I execute user.authentications.last, to get the above Authentication out of the 1 item array, I receive:
< Authentication:0x007f837d32e288 >
Why doesn't it display all the parameters, id, user_id, provider, uid, etc. I can't access and extract the uid this way. I'm trying to run user.authentications.last.uid.
Thank you
What you see here is simply different string representation of the objects. Array's to_s method gives you a nice printout, but Authentication's to_s does not. Try user.authentications.last.inspect if you just want to look at it.

Resources