2016-11-17 7 views
19

この質問は、私が見る限り、これまでに依頼されていますが、まだ回答がありません。だから私はこの質問に再び答えを得るために、この質問をもう一度聞いています。 (私が間違っている場合は、答えのURLを教えてください)どのようにパスワード入力は、ユーザーのすべての文字のアスタリスクを印刷してPythonで行うことができますか?

問題:プログラマーはユーザーにパスワードを入力させたいと思っています。 getpass()関数は、この目的にはうってつけですが、その使用には欠点があります。パスワードを入力している間は、何もstdoutに出力されません。

質問:アスタリスクは、ユーザーが入力した文字ごとに印刷されている間、どのようにGETPASSは()を実装することができますか? (もちろんバックスペース - と理想的POS1エンドが - それに応じての世話をする必要があります。)

動機:この質問が尋ねてきた理由を理解していない地域の人々がありました。そして、getpass()をa)この方法で手を無視して参照してください。b)そのことについて考えずに、その質問に答えないでしょう。なぜs.o.ユーザーの便宜のためにアスタリスクを印刷したいと思うかもしれません:パスワード入力中に直接的な視覚的応答を得ます。そのため、彼らはキーを押すことで混乱することはありません - 目には何も起こっていないようです。

解決に向けたステップ:

私はここで解決への第一歩を提示してみましょう。それを真の解決策に進化させるために助けてください。

標準入力から文字で文字を読んでできるように思わgetchはという名前のモジュールがあります。 Backspaceキーはある - かなり妙 - 127の整数値にマッピングされたが、そのような解決策は、次のようになります。

def readLineWithAsterisks(): 
    sBuffer = '' 
    while True: 
     c = getch.getch() 
     if c == '\n': 
      return sBuffer 
     elif ord(c) == 127: 
      if len(sBuffer) > 0: 
       sys.stdout.write('\x08 \x08') 
       sys.stdout.flush() 
       sBuffer = sBuffer[0:-1] 
      continue 
     else: 
      sys.stdout.write('*') 
      sys.stdout.flush() 
      sBuffer += c 

しかし、このコードはいくつかの欠点を有しています。最初に私は非常に多くのことを混同していますc s.oなら '\ b'ではありません。 バックスペースを入力しました。たぶんs.o.これについての説明がありますか? 2番目のASCII文字は、少なくともLinuxでは処理されます。ここではWindowsについてはわかりませんが、A-Z0-9以外の文字を押すと、c = getch.getch()という行が例外をスローします。 getch()は、ウムラウトや他の種類の文字を少なくともある程度は処理できないようです。次の問題に対処する必要があるソリューションの入力に来て

  • がどのように標準入力からの読み込みは非ASCII文字に関して文字ずつ行うことができますか?
  • これはプラットフォームに依存しない方法でどのように行うことができますか?
  • これはどのようにして安全に行うことができますか(セキュリティ上の問題なし)?(GETPASS何とかこの問題に対処するようだが、私は完全にはどのように理解していない。)

たぶん誰もこのことについて知っています。私の知る限り、これまでに尋ねられたような質問には未回答のままでした。しかし、おそらく、そこにいくつかのソフトウェア開発者がいて、これについてもっと知っていて、ここで助けてくれるコミュニティにいますか?成功すると、GitHubで提供されているソリューションをPythonモジュールとして入手できます。

答えて

-1

おそらく安全ではないが、tkinterを使用する方が簡単かもしれませんが、これは私があなたが求めているものに最も近いものです。

from tkinter import * 
from tkinter import ttk 

root = Tk() 
parent = ttk.Frame(root) 
parent.grid() 

password = ttk.Entry(parent, show="*").grid()#shows each character as an asterix 

root.mainloop() 

申し訳ありません。

0

あなたはそれがMSVCRTのlibを使用するWindowsの場合は
http://code.activestate.com/recipes/134892/

独自のプラットフォームに依存しないソリューションのための出発点として、このレシピはとして有用かもしれません。 getch()の呼び出しをgetwch()に置き換えて、Unicodeを処理することができます。

ActivePython 2.7.10.12 (ActiveState Software Inc.) based on 
Python 2.7.10 (default, Aug 21 2015, 12:07:58) [MSC v.1500 64 bit (AMD64)] on win32 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import msvcrt 
>>> msvcrt.getch() 
'j' 
>>> msvcrt.getch() 
'r' 
>>> msvcrt.getch() 
'?' 
>>> msvcrt.getwch() 
u'\u0432' 
1

注:私の他の答えは、プラットフォームに依存しない方法でこれを行うための作業python2コードが含まれています。

安全なプラットフォームに依存しない方法はgetpass.getpass()と同一のセットアップすべてがそうソース(私のために/usr/lib/python2.7/getpass.py)を見ていきます。それはかなり簡単です。星をエコーについては

...

win_getpass()はすでにちょうどそのループの中でいくつかの*をエコー、charで文字を読んでいます。 msvcrt.getch()の代わりにmsvcrt.getwch()を使用する必要があるかもしれませんが、それはPython getpassモジュールにバグがあることを意味します。

unix_getpass()はトリッキーです。 ECHOが既に無効になっているのと同様に、端末にはcbreakを設定する必要があります(https://utcc.utoronto.ca/~cks/space/blog/unix/CBreakAndRawを参照)。その場合はではなく、_raw_input()を使用してループ内でread(1)win_getpass()と同様)を使用する必要があります。

一度バイト単位で読んでいると、「文字」を構成するものを特定するという苦労を経験することができます。これはエンコーディングに依存し、長さも可変です(UTF-8の場合)。

+0

「それはかなり単純明快である」 - いや、本当に申し訳ありませんが:-)ではなく、誰もがTTYのとそのすべての特殊性:-)に関するすべての詳細を知っている - そして、読んで(1)が有用ではありません:私が知っている限り、STDINはPythonでラインごとに設計されています。これは基本的な問題の1つです。それにもかかわらず、あなたがここで述べた他の情報を見ていきます。それのいくつかは本当に役に立つと思われます。どうもありがとうございました! –

+0

STDINの行処理は、基本的なPythonの問題ではありません。 TTYは従来、クライアント側で行編集を行えるように行バッファリングされていました。また、read(1)は、1バイトを読み取る必要がある場合に非常に便利です。 –

1

jupyter/ipythonがこれをどのように実装したかを見てみたいかもしれません。 getpass()を使用して入力されたすべての文字に対してすぐにドットが表示されます。

enter image description here

+0

ありがとう、私はそれを見てみましょう。 –

+0

上記のコードを使用して私のパスワードをPythonで入力している間にドットが表示されない... –

+0

@ nabin-info何かがセットアップに間違っています - 私はjupyter 4.2.3を使用しています。私はgifアニメーションで自分の答えを更新しました。 – denfromufa

0

私はあなたが独立してそれをプラットフォームを行う大体どのように説明するためにモジュールを書きました。

#!/usr/bin/python2 

def _masked_input_unix(prompt="Password: ", mask="*"): 
    pw = "" 
    # save terminal settings 
    fd = sys.stdin.fileno() 
    old = termios.tcgetattr(fd) 
    new = termios.tcgetattr(fd) 
    # setup 'cbreak' mode 
    new[3] = new[3] & ~termios.ECHO 
    new[3] = new[3] & ~termios.ICANON 
    new[6][termios.VMIN] = '\x01' 
    new[6][termios.VTIME] = '\x00' 
    try: 
     termios.tcsetattr(fd, termios.TCSADRAIN, new) 
     print prompt, 
     # Read the password 
     while True: 
      c = sys.stdin.read(1) 
      # submit chars 
      if c == '\r' or c == '\n': 
       sys.stdout.write("%s" % (c)) 
       break 
      # delete chars 
      elif c == '\b' or c == '\x7f': 
       if len(pw) > 0: 
        pw = pw[:-1] 
        sys.stdout.write("%s" % ('\b \b')) 
      # password chars 
      else: 
       pw += c 
       sys.stdout.write("%s" % (mask)) 
    finally: 
     # ensure we reset the terminal 
     termios.tcsetattr(fd, termios.TCSADRAIN, old) 
    return pw 

def _masked_input_win(prompt="Password: ", mask='*'): 
    pw = "" 
    while True: 
     c = msvcrt.getch() 
     # submit chars 
     if c == '\r' or c == '\n': 
      while msvcrt.kbhit(): 
       msvcrt.getch() 
      print 
      break 
     elif c == '\x03': 
      raise KeyboardInterrupt 
     # delete chars 
     elif c == '\b' or c == '\x7f': 
      if len(pw) > 0: 
       pw = pw[:-1] 
       msvcrt.putch('\b') 
       msvcrt.putch(' ') 
       msvcrt.putch('\b') 
     # password chars 
     else: 
      pw += c 
      msvcrt.putch(mask) 
    return pw 

## initialize windows or posix function pointer 
masked_input = None 
try: 
    import msvcrt 
    masked_input = _masked_input_win 
except ImportError: 
    import sys, termios 
    masked_input = _masked_input_unix 

if __name__ == "__main__": 
    p = masked_input() 
    print "Password is:", p 

これはシングルバイトエンコーディングで使用できます。ユニコードサポートを追加するのは簡単ではありません。私はユニコードがWindowsのgetpassモジュールでうまく動作しないと思われます。(注:これは、Unicode文字列にすべてを変えるとgetwch()を使用するのと同じくらい簡単ではありません)

1

これはLinuxのみのバージョンで、UnicodeでPython 2とPython 3で動作します。

Unicode文字を入力するには、Ctrl+Shiftと同時に入力し、uと入力してCtrl+Shiftを入力し、コードポイントと<Enter>と入力します。

os.reados.writeファンクションを使用して、(libcとpython IO)バッファリングの問題をバイパスし、カーネルからバイトを読み込みます。

ターミナルKILL(^ U)、ERASE(ascii DEL aka Backspaceキー)、EOF(^ D)およびascii BS(\b)に対応しています。

バックグラウンドで入力された文字からの再開時にパスワードが読み取られるため、SIGTSTPを無視します。

import tty 
import os 
import sys 
import signal 
from array import array 

# disable (^Z) SIGTSTP 
signal.signal(signal.SIGTSTP, signal.SIG_IGN) 
stdin = sys.__stdin__.fileno() 
stream = sys.__stderr__.fileno() 
old = tty.tcgetattr(stdin) 
os.write(stream, b"Passwd: ") 
try: 
    tty.setcbreak(stdin) 
    passwd = array("u") 
    while True: 
     # UTF-8 is 4 octets (bytes) at max 
     c = os.read(stdin, 4) 
     # ERASE ascii DEL (0x7f) <Backspace> and ascii BS (0x08) <^H> 
     if c in (old[tty.CC][tty.VERASE], b"\b"): 
      if passwd: 
       os.write(stream, b"\b \b") 
       passwd.pop() 
     # KILL ascii NAK (0x15) <^U> 
     elif c == old[tty.CC][tty.VKILL]: 
      if passwd: 
       os.write(stream, b"\b \b" * len(passwd)) 
       passwd = array("u") 
     # ascii LF (0x0a) <^J>, CR (0x0d) <^M> and <Enter> and EOT (0x04) <^D> 
     elif c in (b"\n", old[tty.CC][tty.VEOF]): 
      break 
     else: 
      #c = c.decode('utf-8') 
      c = c.decode(sys.__stdin__.encoding) 
      passwd.append(c) 
      os.write(stream, b"*") 
finally: 
    # restore terminal settings 
    tty.tcsetattr(stdin, tty.TCSAFLUSH, old) 
    # enable (^Z) SIGTSTP 
    signal.signal(signal.SIGTSTP, signal.SIG_DFL) 
    os.write(stream, b"\n") 

print(passwd.tounicode()) 

テスト;

$ # To input "Þàsswõrd" 
$ # U+00de, U+00e0, s,s, w, U+00f5, r, d 
$ python getpass.py 
$ Passwd: ******** 
Þàsswõrd 
関連する問題