Automate the boring stuff with Python chapter 6 Password locker - python

#! python3
# pw.py - An insecure password locker program.
PASSWORDS = {'email': 'F7minlBDDuvMJuxESSKHFhTxFtjVB6',
'blog': 'VmALvQyKAxiVH5G8v01if1MLZF3sdt',
'luggage': '12345'}
import sys, pyperclip
if len(sys.argv) < 2:
print('Usage: py pw.py [account] - copy account password')
sys.exit()
account = sys.argv[1] # first command line arg is the account name
if account in PASSWORDS:
pyperclip.copy(PASSWORDS[account])
print('Password for ' + account + ' copied to clipboard.')
else:
print('There is no account named ' + account)
I really don't know what to do. After running win+r and typing e.g. pw email i get only 'usage:py bla bla bla.. nothing else whatever i wrote in win+r
the bat file is like:
'''call C:\Users\Rostek\anaconda3\Scripts\activate.bat
C:\Users\Rostek\anaconda3\python.exe "C:\Users\Rostek\.spyder-py3\Projekty\pw.py"
#pause'''
I cannot pass the arguments I think. I have read all the internet and found nothing like this.
please help. It's program from the book. I am using anaconda3.

You might want to think about what your problem is supposed to do.
if len(sys.argv) < 2:
print('Usage: py pw.py [account] - copy account password')
sys.exit()
This clearly does what it should.
Your question is actually not about python, but about win+r passing arguments.
Why do you want to run your program with win+r in the first place?
After running win+r and typing e.g. pw email...
What you want is to open the command line/ powershell/ bash instead and simply pass the variables to your programm with python3 programname.py email directly.
If you want to do that even cleaner you should use an argparser.
EDIT:
After the clarification in the comments:
The problem is that if you execute a script with win+r you will get the output- for a fraction of a second- then the cmd is closed...
So unless you specify a location in your script to where the pw is written to, you´ll have it in your console. Which blinks and vanishes immediately. Therefore open a console and execute the program from there.
Or you might want to have a look at this:
Output to clipboard

Related

using subprocess.run to automate a command line application (windows 10)

trying to use python to automate a usage of a command line application called slsk-cli
manually, the procedure is straight-forward - i open a command prompt window and type 'soulseek login', then a prompt requests username, after i type in and press enter i'm requested a password.
so far, i manage to get the prompt of the username but not getting passed that.
subprocess.run('soulseek login',shell=True)
this results in the ?Login output in the python console but also the process is stuck, when i run in debug or also in run
is there a better way to go about this?
Interacting continuously with a system via subprocess can be tricky. However, it seems that your interface prompts are one after the other, which can therefore be chained together, via newline characters which act as Return key strokes.
For example, the program shown below simply prompts a user for their username and a password, to which the 'user' (your script) provides the input via the proc.communicate() method. Once these are provided, the user is asked if they'd like to continue (and do the same thing again). The following subprocess call feeds the following input into the prompter.py script:
username
password
continue reply (y or n)
Example code:
import subprocess
uid = 'Bob'
pwd = 'MyPa$$w0rd'
reply = 'n'
with subprocess.Popen('./prompter.py',
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
text=True) as proc:
stdout, stderr = proc.communicate(input='\n'.join([uid, pwd, reply]))
Output:
# Check output.
>>> print(stdout)
Please enter a username: Password: uid='Bob'
pwd='MyPa$$w0rd'
Have another go? [y|n]:
# Sanity check for errors.
>>> print(stderr)
''
Script:
For completeness, I've included the contents of the prompter.py script below.
#!/usr/bin/env python
from time import sleep
def prompter():
while True:
uid = input('\nPlease enter a username: ')
pwd = input('Password: ')
print(f'{uid=}\n{pwd=}')
sleep(2)
x = input('Have another go? [y|n]: ')
if x.lower() == 'n':
break
if __name__ == '__main__':
prompter()

How can I execute OS Commands with Python pexpect?

I want to execute a python script, which switches to another user by automatically writing the user password. Both users have no root rights. After the login I want to execute the OS Commands "whoami" to check if the login was successful. Here's the code:
child = pexpect.spawn('su - otheruser)
child.expect_exact('Password:')
child.sendline('password')
print("logged in...")
child.expect('')
child.sendline('whoami')
print(child.before)
I want to print the output from the command to the console (just for debugging) but the output is like "b272' (a combination of random letters) and not the actual whoami user. How can I fix that?
Later I want to create from the switched user some files and so on. So basically, I want to execute OS Commands in a python script which is logged in an other user.
Pexpect searches are not greedy, so it will stop at the first match. When I tested your code with before, match.groups(), after, and buffer, I didn't get an EOF or TIMEOUT, so it must have matched right at the beginning of the read and returned nothing (I'm surprised you got any results at all).
I recommend always following a sendline with an expect, and the end of a prompt (]$) is a good thing to expect, instead of an empty string.
Here is my take on your code, including creating a file:
NOTE - Tested on Centos 7.9, using Python 2.7.
import pexpect
child = pexpect.spawn("su - orcam")
child.expect_exact("Password:")
child.sendline("**********")
child.expect_exact("]$")
print("Logged in...\n")
child.sendline("whoami")
child.expect_exact("]$")
print(child.before + "\n")
child.sendline("echo -e 'Hello, world.' >> hello.txt")
child.expect_exact("]$")
child.sendline("cat hello.txt")
child.expect_exact("]$")
print(child.before + "\n")
child.sendline("exit")
index = child.expect_exact(["logout", pexpect.EOF, ])
print("Logged out: {0}".format(index))
Output:
Logged in...
whoami
orcam
[orcam#localhost ~
cat hello.txt
Hello, world.
[orcam#localhost ~
Logged out: 0

raw_input() prompt disappears when redirecting output to file

I am writing a CLI that accepts an email and password for auth.
The email prompt uses raw_input() and the password prompt uses getpass() for obfuscation.
This setup works fine when outputting directly to console, but falters when redirecting the output to a log file.
Sample code:
user_email = raw_input('Email: ')
user_password = getpass('Password: ')
Sample output without redirection:
$ python script_that_does_stuff.py
Email: me#email.com
Password:
Doing stuff...
Sample output with redirection:
$ python script_that_does_stuff.py > stuff.log
Because I know that it's expecting a user input here, I can type the email, hit enter, and then it will show:
$ python script_that_does_stuff.py > stuff.log
me#email.com
Password:
After inputting a password, it continues as usual, however the log shows the following:
$ cat stuff.log
Email:Doing stuff...
Question:
How can I force the raw_input() prompt to show up in console like the getpass() prompt does when redirecting output to a file?
Environment
This script lives in a legacy Python 2.7 codebase, and is run primarily on Mac OS systems, occasionally Linux.
You can override sys.stdout temporarily to write to the terminal. For example,
import contextlib
import sys
#contextlib.contextmanager
def output_to_terminal():
try:
with open("/dev/tty") as f:
sys.stdout = f
yield
finally:
# Ensure sys.stdout is restored in the event of an error
sys.stdout = sys.__stdout__
with output_to_terminal():
x = raw_input("> ")
print(x)
(This was derived independently; you may want to check source for Python 3's redirect_stdout, also found in the contextlib module, and back port it for your use.)
This answer on another question seems to work for me.
In short, create a custom input function:
def email_input(prompt=None):
if prompt:
sys.stderr.write(str(prompt))
return raw_input()
The calling code then becomes:
user_email = email_input('Email: ')
user_password = getpass('Password: ')
This results in both the Email and Password prompts being sent to stderr (printing to console), and not messing with the redirected log output.
According to official documentation getpass([prompt[, stream]]) has the second optional parameter which indicates output stream to print the prompt to (stderr by default).
When you redirect the output (stdout) the prompt is still printed to stderr for getpass but raw_input does not support setting an output stream so its prompt is redirecting to to the target file.
So to solve your issue, you have to print your prompt to stderr for email as well.

How to use sys.argv in python to check length of arguments so it can run as script?

Ok so here is part of my code (I have imported sys)
if __name__ == '__main__':
MyCaesarCipher = CaesarCipher() #MyCaesarCipher IS a CaesarCipher()
if len(sys.argv) >1:
#what will it check?
Done = False
while not Done:
print('C Clear All')
print('L Load Encrypted File')
print('R Read Decrypted File')
print('S Store Encrypted File')
print('W Write Decrypted File')
print('O Output Encrypted Text')
print('P Print Decrypted Text')
print('E Encrypt Decrypted Text')
print('D Decrypted Encrypted Text')
print('Q Quit')
print('----------------')
print('Enter Choice>')
So the thing is I want to do is if the command line length is more than 1, the program runs as a script.
This is the instruction:
If no command line arguments are input, then the script enters menu
mode. If more than 1 command line argument (anything other than script
name) is provided during the run of the script it enters single run
mode.
I do not know what this means, though.
What is sys.arvg:
The list of command line arguments passed to a Python script. argv[0] is the script name.
Demo:
File Name: 1.py
import sys
if __name__=="__main__":
print "command arguments:", sys.argv
Output:
$ python 1.py arg1 arg2
command arguments: ['1.py', 'arg1', 'arg2']
$ python 1.py
command arguments: ['1.py']
Your problem is, we have to run code by Command Line Argument and by Menu also.
When User provided the Enter Choice from the command line then use provided value to next process.
If User not provided the Enter Choice from the command line then ask User to Enter Choice from the Menu.
Demo:
File Name: 1.py
import sys
if __name__ == '__main__':
try:
arg_command = sys.argv[1]
except IndexError:
arg_command = ""
Done = False
while not Done:
if arg_command=="":
print('\nMenu')
print('C Clear All')
print('L Load Encrypted File')
print('Q Quit')
print('----------------')
print('Enter Choice>')
command = raw_input('Enter Selection> ').strip()[0].upper()
else:
command = arg_command
#- set arg value to empty to run Menu option again.
arg_command = ""
if command == 'C':
print "In Clear All event."
elif command == 'L':
print "In Clear All event."
elif command == "Q":
break
else:
print "Wrong Selection."
Output:
Enter Choice given from the Command Line:
$ python 1.py C
In Clear All event.
Menu
C Clear All
L Load Encrypted File
Q Quit
----------------
Enter Choice>
Enter Selection> q
$
No Command Line argument.
$ python 1.py
Menu
C Clear All
L Load Encrypted File
Q Quit
----------------
Enter Choice>
Enter Selection> l
In Clear All event.
Menu
C Clear All
L Load Encrypted File
Q Quit
----------------
Enter Choice>
Enter Selection> q
$
Here's the thing, when you're learning a language like this, you can often get by pretty well with just printing out things you don't really understand.
Try this:
Step 1) Make a program that looks like this:
import sys
if __name__ == '__main__':
for idx, arg in enumerate(sys.argv):
print("arg #{} is {}".format(idx, arg))
print len(sys.argv)
After that, run your program from the command line like this:
$ python3 test_script.py
Then, run it like this:
$ python3 test_script.py somearg someother andanother etc "23908452359"
What you discover may be useful to perform this task you are looking to resolve.
Lastly, "menu mode" sounds like the script is going to take input from the user. Thus, you'll need to use input() to do that. It also sounds like you need to come to some decision about when to use menu mode or not, which you've already started to do with your if-test above.
Experiment a bit, though, and you'll figure it out.
The instructions want the script to use the command line arguments to execute the script.
python script.py [arg1] [arg2] [arg3] ....
The args are accessible through sys.argv.
sys.argv = ['script.py', '[arg1]', '[arg2]', '[arg3]']
You will need to use a command line interface instead of the menu interface when args are present.
Since you seem to be pretty new to python here's a simple example using your code. You'll have to complete the menu and the actual code for the menu options but it does use sys.argv
import sys
def menu():
Done = False
while not Done:
print('C Clear All')
print('L Load Encrypted File')
print('R Read Decrypted File')
print('S Store Encrypted File')
print('W Write Decrypted File')
print('O Output Encrypted Text')
print('P Print Decrypted Text')
print('E Encrypt Decrypted Text')
print('D Decrypted Encrypted Text')
print('Q Quit')
print('----------------')
print('Enter Choice>') #should get user input here
Done = True
if __name__=="__main__" :
if len(sys.argv) > 1 :
#Here if an argument is present run it or load the menu
print "run whatever option was entered on the commandline"
else:
menu()
First of all you have to understand what argv is, try creating this script, and call it learning_argv.py
import sys
print(sys.argv)
now try running the script like this:
$ python3 learning_argv.py
$ python3 learning_argv.py a
$ python3 learning_argv.py a b c
$ python3 learning_argv.py AWESOME TEXT
See what argv is?
What you're doing when you test if the length of argv is bigger than one, is basically testing if you're receiving anything beyond the script name.
In the future, you could create a similar structure you created for your menu, to treat arguments sent directly from the command line.
take a look at this quick tutorial in order to better understand argv.

Rsync command not working with python

I am trying implement rsync with python. Here's my code.
#!/usr/bin/python
import os
url = raw_input("Paste your URL:")
username = raw_input("Enter username:")
#password = raw_input("Enter password:")
source = username + "#" + url
#print source
print os.system('rsync -zvr --progress source /home/zurelsoft/R')
The logic is simple: user inputs the url and username stored in source with proper formatting. The source variable is then used in rsync command. I am inputting the valid URL and username of my server but I am getting this error:
rsync: link_stat "/home/name/source" failed: No such file or directory (2)
What am I doing wrong?
You're passing a static string. Regardless of what the user inputs, you're always giving rsync the exact same commandline options. You probably want source to be replaced with the value:
print os.system('rsync -zvr --progress {source} /home/zurelsoft/R'.format(source=source))
As a side note, this can be done better with subprocess :
subprocess.call(['rsync','-zvr','--progress',source,'/home/zurelsoft/R'])
It might not matter, but you'll close a HUGE security hole in your program this way (consider if the user put ; rm -rf ~; as their username ...) and it's always a good idea practice good programming habits.
Use subprocess.call
subprocess.call(["rsync", "-avz", "--exclude-from", "/tmp/exclude-list.txt", source, destination])
or if you need out put,
output = subprocess.Popen(["rsync", "-avz", "--exclude-from", "/tmp/exclude-list.txt", source, destination])

Categories

Resources