Rclone authorization automatic

These are for writing How To Guides and not for general support.

If you have a support question, please use the Help and Support Template.


For the people who use Rclone with Google drive and set up their own client ID and secret and are frustrated with having to renew the authorization every 7 days, I've figured out some scripting to automate it as much as possible

Requirements (to the best of my knowledge)
Python 3
Rclone gdrive configured

Basically my approach has been to use an expect script to automate the Rclone config command to renew the authorization token, I haven't found an easier way than this so far so I thought I'd share my approach and code as well if anyone is interested

The code consists of 3 different scripts, the two python ones could definitely be made into one, you will need to alter all three to make it work

First is the expect script

#!/usr/bin/expect -f

set timeout -1

set rclonePID [spawn -noecho rclone config]
set rcloneID $spawn_id
send_user "$rclonePID $rcloneID \n"

expect "e/n/d/r/c/s/q> "
send -i rcloneID "e\r"
expect "remote> "
send -i rcloneID "1\r"
expect "y/n> "
send -i rcloneID "n\r"
expect "y/n> "
send -i rcloneID "n\r"
expect "y/n> "
send -i rcloneID "n\r"
expect "y/n> "
send -i rcloneID "n\r"
expect "y/n> "
send -i rcloneID "n\r"
expect "y/n> "
send -i rcloneID "n\r"
expect "y/e/d> "
send -i rcloneID "y\r"
expect "y/n> "
send -i rcloneID "y\r"
expect "y/n> "
send -i rcloneID "n\r"
#at yhis point it gives link
expect "following link: "
expect "\n"
set link $expect_out(buffer)
expect "Enter verification code> "

set pythonPID [spawn -noecho ~/python/sendEmailWaitReply.py "Rclone Link\n" $link extra ]
set pythonID $spawn_id
expect "Email Sent"
expect "\n"
expect "\n"
set verifyCode $expect_out(buffer)

#send_user "AAAAA$verifyCode"

set spawn_id $rcloneID
send -i rcloneID "$verifyCode\r"

expect {
-re "failed"    {send_user "FAILED"; close}
-re "y/n> "     {send -i rcloneID "n\r"}
expect "e/n/d/r/c/s/q> "
send -i rcloneID "q\r"
expect eof

The only changes necessary would be the paths to the python script

Next is an email class to text you the link

#!/usr/bin/env python3

import smtplib

import email
import imaplib

#Email Variables
SMTP_SERVER = 'smtp.gmail.com' #Email Server (don't change!)
SMTP_PORT = 587 #Server Port (don't change!)

IMAP_SERVER = 'imap.gmail.com'

GMAIL_USERNAME = 'YPUREMAILHERE@gmail.com' #change this to match your gmail account
GMAIL_PASSWORD = 'zhbgqbwtrtmvgmfd'  #change this to match your gmail APP password, NOT YOUR ACTUAL PASSWORD

class Emailer:
    def sendmail(self, recipient, subject, content):

        #Create Headers
        headers = ["From: " + GMAIL_USERNAME, "Subject: " + subject, "To: " + recipient,
                   "MIME-Version: 1.0", "Content-Type: text/plain"]
        headers = "\r\n".join(headers)

        #Connect to Gmail Server
        session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)

        #Login to Gmail
        session.login(GMAIL_USERNAME, GMAIL_PASSWORD)

        #Send Email & Exit
        session.sendmail(GMAIL_USERNAME, recipient, headers + "\r\n\r\n" + content)

class Reciever:
        def checkmail(self,fromWho):
                mail = imaplib.IMAP4_SSL(IMAP_SERVER)
                mail.login(GMAIL_USERNAME, GMAIL_PASSWORD)
                status, data = mail.search(None,f'(FROM "{fromWho}")' )
                ids = data[0] # data is a list.
                id_list = ids.split() # ids is a space separated string
                latest_email_id = id_list[-1] # get the latest
                result, data = mail.fetch(latest_email_id, "(RFC822)") # fetch the email body (RFC822)             for the given ID
                for response_part in data:
                        if isinstance(response_part, tuple):
                                message = email.message_from_bytes(response_part[1])
                                mail_subject = message['subject']
                                mail_from = message['from']
                                mail_time = message['date']
                                if message.is_multipart():
                                        mail_content = ''
                                        for part in message.get_payload():
                                                if part.get_content_type() == 'text/plain':
                                                        mail_content += part.get_payload()
                                        mail_content = message.get_payload()
#                       print(f'From: {mail_from}')
#                       print(f'Subject: {mail_subject}')
#                       print(f'Content: {mail_content}')
#                       print(f'Date: {mail_time}')

                return mail_time, mail_content

last is a script to send and wait for the next email, assuming it has just the authorization code in it

#!/usr/bin/env python3

import emailClassNew
import sys
import time, datetime

sender = emailClassNew.Emailer()
sendTo = 'YOURNUMBERHERE@vzwpix.com'
replyFrom = 'YOURNUMBERHERE@vtext.com'
emailSubject = str(sys.argv[1])
emailContent = str(sys.argv[2])

sender.sendmail(sendTo, emailSubject, emailContent)
sentTime = datetime.datetime.now(datetime.timezone.utc)
print("Email Sent")
rec = emailClassNew.Reciever()
foundText = False

while not foundText:
        global recieved
        time, recieved = rec.checkmail(replyFrom)
        time = time[:-5]

        format = "%a, %d %b %Y %H:%M:%S %z "
        recievedTime = datetime.datetime.strptime(time,format)
        foundText = (recievedTime > sentTime)

this is a very crude code I just figured out but maybe it will help you refine it and not have to worry about your automatic backups not working do to authorization

You would run the .exp script weekly with cron then all you need to do is click the link in your text and reply with the code

Warning, this is not debugged at all