http://www.perlmonks.org?node_id=974080

Watergun has asked for the wisdom of the Perl Monks concerning the following question:

Hi guys, I just joined minutes ago and I'd first like to say hello. I'm a student with an assignment on hand to program a basic password manager. This line shows how I can show and decode the data

I am using a cygwin terminal, btw.

perl passmgr0957.pl L abc Facebook

Where L is the option command to List, abc is the decode key and Facebook is the search string to search for the password for the user's Facebook account. The search string is to be OPTIONAL, and I am terribly boggled by this because I haven't learnt how to work with optional arguments.

Can someone help me out, teach me how I can go about writing this?

This is my full code if needed. ST2614 is a module my lecturer provided to decode and encode using an XOR format (As what he told me)

A million thanks to any kind soul who can help!

#!/usr/bin/perl -w use strict; use warnings; use ST2614 1.0; #subroutine guide provides user a simple documentation on how to use t +he password manager sub guide { my $pwdmgr = shift; print "usage: $pwdmgr L key [site_pattern]\n"; print "-"x5, " takes the encoding key and optional site_pattern to + retrieve all saved entries that match.\n If no site_pattern, retrieve all s +aved entries\n\n"; print "usage: $pwdmgr U key site_name login_id password [URL]\n"; print "-"x5, " Using the encoding key, add new or update existing +entry.\n Complete set of entry info required: Site name, login id, password, URL(Optional)\ +n\n"; print "usage: $pwdmgr D key site_name\n"; print "-"x5, " Takes in encoding key and site_name to delete entry +; will only work if encoding key matches and entry found matching with site_name.\n"; exit; } #an if-elsif loop to check which option user has selected if ($ARGV[0] eq "L") { sub listFunct ($;$) { open(FILEHANDLE, "passmgr.dat") or die ("The file cannot be op +ened!"); my $decode = ST2614::decode(FILEHANDLE, $ARGV[1]); } } elsif ($ARGV[0] eq "U") { #declare the individual variables that are to be stored my $sitename = $ARGV[2]; #sitename will be the key in the hash of +array my $loginid = $ARGV[3]; my $password = $ARGV[4]; my $url = $ARGV[5]; #declare a hash of array to prepare storage of all variables to be + encoded together my HoA {$sitename} = ["$loginid", "$password", "$url"];; open(FILEHANDLE, ">>passmgr.dat") or die("The file cannot be opene +d!"); my $encode = ST2614::encode(HoA, $ARGV[1]); print FILEHANDLE "$encode"; close FILEHANDLE; print "Data successfully encoded. Please remember your key.\n Your + key is $ARGV[1]."; } elsif ($ARGV[0] eq "D") { } else { guide($0); }

Replies are listed 'Best First'.
Re: Optional Arguments..?
by davido (Cardinal) on Jun 03, 2012 at 03:16 UTC

    The array, @ARGV contains the various arguments passed on the command line. To access the first element by index, it would be $ARGV[0]. You're using that first element to handle the command line switch, L, U or D. The second arg is $ARGV[1], and that's where you're passing the key. The third (optional) parameter is $ARGV[2]. That element will either have a value, or it will be undefined. To detect which, you might do something like this:

    if( defined $ARGV[2] ) { # Handle the search string. } else { # Perform whatever default preparations are necessary in # the absence of a defined search string. }

    So the key is to test $ARGV[2] for definedness. There are a couple of useful ways to do that. The most common by far is the defined built-in function. But there's also the // and //= operators, described in perlop. With //=, you could do something like this:

    $ARGV[2] //= 'Default value';

    In this case, if $ARGV[2] already contains a value, the line has no effect.  If it doesn't contain a value, '<c>Default value' is assigned.

    Using the // operator might look like this:

    my $pattern = $ARGV[2] // 'Default value';

    Here, $pattern receives the contents of $ARGV[2] if $ARGV[2] is defined. If it's undefined, then 'Default value' is assigned to $pattern.

    The // and //= operators were introduced to Perl in version 5.10.0 (I think). So they won't work if you're stuck using older versions. defined works all the way back to the earliest Perl 5 versions, and possibly more.

    Welcome to Perl! :)


    Dave

      Hi Dave!

      Firstly I wanna say I almost burst into happiness when you explained this.. "defined" to me. It's the one thing that my lecturer told us to google for, to implement in our codes but I just couldn't find a simple explanation to use this. Thanks a lot. Right now after using defined, my code looks like this

      #!/usr/bin/perl -w use strict; use warnings; use ST2614 1.0; #subroutine guide provides user a simple documentation on how to use t +he password manager sub guide { my $pwdmgr = shift; print "usage: $pwdmgr L key [site_pattern]\n"; print "-"x5, " takes the encoding key and optional site_pattern to + retrieve all saved entries that match.\n If no site_pattern, retrieve all s +aved entries\n\n"; print "usage: $pwdmgr U key site_name login_id password [URL]\n"; print "-"x5, " Using the encoding key, add new or update existing +entry.\n Complete set of entry info required: Site name, login id, password, URL(Optional)\ +n\n"; print "usage: $pwdmgr D key site_name\n"; print "-"x5, " Takes in encoding key and site_name to delete entry +; will only work if encoding key matches and entry found matching with site_name.\n"; exit; } #an if-elsif loop to check which option user has selected if ($ARGV[0] eq "L") { sub listFunct ($;$) { open(FILEHANDLE, "passmgr.dat") or die ("The file cannot be op +ened!"); my $decode = ST2614::decode(FILEHANDLE, $ARGV[1]); if ( defined $ARGV[2] ) { for $decode (keys =~ m/$ARGV[2]/) { print "$decode: @{ m/$ARGV[2]/ {$decode} }\n"; + } } else { for $decode () { print } } } } elsif ($ARGV[0] eq "U") { #declare the individual variables that are to be stored my $sitename = $ARGV[2]; #sitename will be the key in the hash of +array my $loginid = $ARGV[3]; my $password = $ARGV[4]; my $url = $ARGV[5]; #declare a hash of array to prepare storage of all variables to be + encoded together my HoA {$sitename} = ["$loginid", "$password", "$url"];; open(FILEHANDLE, ">>passmgr.dat") or die("The file cannot be opene +d!"); my $encode = ST2614::encode(HoA, $ARGV[1]); print FILEHANDLE "$encode"; close FILEHANDLE; print "Data successfully encoded. Please remember your key.\n Your + key is $ARGV[1]."; } elsif ($ARGV[0] eq "D") { } else { guide($0); }

      What I want to achieve is to be able to print all password and related data by searching for the sitename, so for example searching for 'a' might give me yahoo and facebook, and list the passwords accordingly. Is my following code correct?

      Also, I would like to be able to print all hashes of arrays in my decoded file, how do I do that?

      With thanks Junming

        It's the one thing that my lecturer told us to google for, to implement in our codes but I just couldn't find a simple explanation to use this.

        Google is great, but I'm surprised your professor didn't mention the Perl documentation. It's included free of charge with every Perl distribution, and also at http://perldoc.perl.org. You can read about defined on your own terminal by typing "perldoc -f defined".

        Is my following code correct?

        No.

        Well... your use of defined is reasonable, but besides that, NO. It doesn't compile.

        Why would you post code that doesn't compile except to possibly ask why it doesn't? You can check yourself, at which point you can begin working through the error messages. For example, "Not enough arguments for keys at mytest.pl line 27, near "keys =~"" Your line numbers will probably be different, but that error message will still be there, unless the code you posted isn't what's in your editor.

        There's no need for me to enumerate the error messages you're getting; Perl will do it for you when you type perl -c mytest.pl, where "mytest.pl" is the name of your script. Once you resolve the issues that perl -c tells you about, you'll run into other problems as well, such as your strange for loop around line 31. It seems to set a topical variable, but the list of items it iterates over is empty, and the print statement on the next line tries to print $_, which isn't going to contain anything meaningful.

        Really, there are enough problems you probably should sit down with your instructor for a half hour and go over them together.

        If you don't have it already, get yourself a copy of Learning Perl, and start reading. It will begin to flow before you know it. And remember this slightly gentler version of a famous quote within the Perl community: "You can't just make stuff up and expect the computer to know what you mean." Programming rewards attention to detail.


        Dave

Re: Optional Arguments..?
by tobyink (Canon) on Jun 03, 2012 at 08:09 UTC

    I would strongly suggest using Getopt::Long. It takes all the headaches out of processing command-line parameters. I'd go as far as saying that if you're processing a command-line, and you want to do anything other than accept a plain old list of filenames, then you're a fool not to use it. Unless of course, that would be disallowed by the guidelines for your assignment.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

      Only a guess, but I suspect at least some of the code is boilerplate supplied by the professor (the portions of the code lacking in syntax errors). Might be best to just stick to the assignment for now.

      Like I said... only a guess.


      Dave

      I'm fairly sure that the assignment doesn't allow for use of modules not covered in the class.

      More to the point, though, so far as I'm aware, Getopt only recognizes options with a - or -- prefix. In this spec, the operation is specified with L, U, or D, not -L/-U/-D, so I don't think Getopt would even work here without changing the interface to the program.

        Hi guys, thanks for the posts. I'm currently back to work on my assignment. Anyway, all of the code that is from me is written by me. My lecturer only provided a module (is it called a module?) named ST2614, which helps encode and decode my hashes. Will update if I have more questions.

        Thanks a million!

        UPDATE: Okay, I managed to figure out what I want to ask. The problem is this: I have to decode the encrypted file of hashes, when I manage to decode it, I declare the result to a variable. Is this correct?

        Second, I want to first print only all hashes that match the argument "site name" where a user might enter 'a' and some example results are hashes with key names such as Yahoo or Facebook printed. How can I do this?

        Lastly, I would like to print all hashes that are decoded. However as I declared the decoded data into a variable, I don't think I can code the program like a typical print-all-hashes that Dave provided.. There seems like something I'm supposed to do, but honestly.. I'm clueless. So I'd like to ask how I could do this as well.

        For the last blank, D, it's meant to be able to delete hashes which key exactly matches the one stated by the user. I haven't started work on it, hence I left it blank.

        Once again thank you guys for the help. It's the holidays in my country over here, and I have trouble contacting my lecturer. This is why I cannot contact him for questions.

Re: Optional Arguments..?
by poj (Abbot) on Jun 03, 2012 at 12:45 UTC
    Could you please show the code for the encode, decode routines. The arguments you have in these statements don't look right to me.
    my $decode = ST2614::decode(FILEHANDLE, $ARGV[1]); my $encode = ST2614::encode(HoA, $ARGV[1]);
    poj
      Hello, here is the code.
      #/usr/bin/perl -w # Demo Version - # AY2012/2013 ST2614 Assignment # PM to support Personal Password Manager package ST2614 ; our $VERSION = 1.0; sub getAscii { # This is a helper function to support encode() and decode() # #input a normal string # convert each char of the string to its corresponding ascii cod +e # return the list of the ascii codes # in one , delimited string my $plaintext= shift; my @asciilist = (); my @tmplist = split('', $plaintext); foreach $ch (@tmplist) { push (@asciilist, ord($ch)); # use ord to get ascii code } return join(",",@asciilist); } sub encode { # simple xor encoding # Argument 1 - A string in plain text - to be encoded # Argument 2 - A string in plain text, represent the key # return the xor result in ascii form my ($text , $key) = @_; $text = getAscii($text); $key = getAscii($key); my @textlist = split(',',$text); my @keyblk = split(',',$key); my $index = 0; my $max = @keyblk; my @encodedlist = (); foreach $chcode (@textlist) { # simple xor encoding # must use int() to force a numeric xor operation my $secret = int($chcode) ^ int($keyblk[$index]); push(@encodedlist,$secret); # store the result # recycle the key block $index = ($index+1) % $max; } return join(",",@encodedlist); } sub decode { # simple xor decoding # Argument 1 - encoded string in ascii list form # Argument 2 - A string in plain text, represent the key # return the xor result in plain text string form my ($secret , $key) = @_; $key = getAscii($key); # break the line into array and xor with the keyblock my @secretlist = split(',',$secret); my @keyblk = split(',',$key); my $index = 0; my $max = @keyblk; my $orgText = ""; foreach $chcode (@secretlist) { my $org = int($chcode) ^ int($keyblk[$index++]); # convert numeric ascii value back to character form # and append it to $orgText $orgText .= chr($org); $index = $index % $max; } return $orgText; } 1; # required to return 1 at the end of a pm file
        OK, looks like arguments are text strings, not a filehandle or a hash ref. Can you show some lines of data from the passmgr.dat file.
        poj