Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
ZEO
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
ZEO
Commits
20319afd
Commit
20319afd
authored
Apr 29, 2003
by
John Dahlin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Initial checkin of AuthZEO (without SRP)
parent
b9c4b220
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
347 additions
and
10 deletions
+347
-10
src/ZEO/ClientStorage.py
src/ZEO/ClientStorage.py
+52
-3
src/ZEO/Exceptions.py
src/ZEO/Exceptions.py
+2
-0
src/ZEO/ServerStub.py
src/ZEO/ServerStub.py
+4
-1
src/ZEO/StorageServer.py
src/ZEO/StorageServer.py
+74
-3
src/ZEO/runzeo.py
src/ZEO/runzeo.py
+7
-3
src/ZEO/tests/testAuth.py
src/ZEO/tests/testAuth.py
+101
-0
src/ZEO/zpasswd.py
src/ZEO/zpasswd.py
+107
-0
No files found.
src/ZEO/ClientStorage.py
View file @
20319afd
##############################################################################
##############################################################################
#
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# Copyright (c) 2001, 2002
, 2003
Zope Corporation and Contributors.
# All Rights Reserved.
# All Rights Reserved.
#
#
# This software is subject to the provisions of the Zope Public License,
# This software is subject to the provisions of the Zope Public License,
...
@@ -29,7 +29,8 @@ import types
...
@@ -29,7 +29,8 @@ import types
from
ZEO
import
ClientCache
,
ServerStub
from
ZEO
import
ClientCache
,
ServerStub
from
ZEO.TransactionBuffer
import
TransactionBuffer
from
ZEO.TransactionBuffer
import
TransactionBuffer
from
ZEO.Exceptions
\
from
ZEO.Exceptions
\
import
ClientStorageError
,
UnrecognizedResult
,
ClientDisconnected
import
ClientStorageError
,
UnrecognizedResult
,
ClientDisconnected
,
\
AuthError
from
ZEO.zrpc.client
import
ConnectionManager
from
ZEO.zrpc.client
import
ConnectionManager
from
ZODB
import
POSException
from
ZODB
import
POSException
...
@@ -99,7 +100,8 @@ class ClientStorage:
...
@@ -99,7 +100,8 @@ class ClientStorage:
min_disconnect_poll
=
5
,
max_disconnect_poll
=
300
,
min_disconnect_poll
=
5
,
max_disconnect_poll
=
300
,
wait_for_server_on_startup
=
None
,
# deprecated alias for wait
wait_for_server_on_startup
=
None
,
# deprecated alias for wait
wait
=
None
,
# defaults to 1
wait
=
None
,
# defaults to 1
read_only
=
0
,
read_only_fallback
=
0
):
read_only
=
0
,
read_only_fallback
=
0
,
username
=
''
,
password
=
''
):
"""ClientStorage constructor.
"""ClientStorage constructor.
...
@@ -159,6 +161,17 @@ class ClientStorage:
...
@@ -159,6 +161,17 @@ class ClientStorage:
writable storages are available. Defaults to false. At
writable storages are available. Defaults to false. At
most one of read_only and read_only_fallback should be
most one of read_only and read_only_fallback should be
true.
true.
username -- string with username to be used when authenticating.
These only need to be provided if you are connecting to an
authenticated server storage.
password -- string with plaintext password to be used
when authenticated.
Note that the authentication scheme is defined by the server and is
detected by the ClientStorage upon connecting (see testConnection()
and doAuth() for details).
"""
"""
log2
(
INFO
,
"%s (pid=%d) created %s/%s for storage: %r"
%
log2
(
INFO
,
"%s (pid=%d) created %s/%s for storage: %r"
%
...
@@ -217,6 +230,8 @@ class ClientStorage:
...
@@ -217,6 +230,8 @@ class ClientStorage:
self
.
_conn_is_read_only
=
0
self
.
_conn_is_read_only
=
0
self
.
_storage
=
storage
self
.
_storage
=
storage
self
.
_read_only_fallback
=
read_only_fallback
self
.
_read_only_fallback
=
read_only_fallback
self
.
_username
=
username
self
.
_password
=
password
# _server_addr is used by sortKey()
# _server_addr is used by sortKey()
self
.
_server_addr
=
None
self
.
_server_addr
=
None
self
.
_tfile
=
None
self
.
_tfile
=
None
...
@@ -347,6 +362,34 @@ class ClientStorage:
...
@@ -347,6 +362,34 @@ class ClientStorage:
if
cn
is
not
None
:
if
cn
is
not
None
:
cn
.
pending
()
cn
.
pending
()
def
doAuth
(
self
,
protocol
,
stub
):
if
self
.
_username
==
''
and
self
.
_password
==
''
:
raise
AuthError
,
"empty username or password"
# import the auth module
# XXX: Should we validate the client module that is being specified
# by the server? A malicious server could cause any auth_*.py file
# to be loaded according to Python import semantics.
fullname
=
'ZEO.auth.auth_'
+
protocol
try
:
module
=
__import__
(
fullname
,
globals
(),
locals
(),
protocol
)
except
ImportError
:
log
(
"%s: no such an auth protocol: %s"
%
(
self
.
__class__
.
__name__
,
protocol
))
# And setup ZEOStorageClass
Client
=
getattr
(
module
,
'Client'
,
None
)
if
not
Client
:
log
(
"%s: %s is not a valid auth protocol, must have a "
+
\
"Client class"
%
(
self
.
__class__
.
__name__
,
protocol
))
raise
AuthError
,
"invalid protocol"
c
=
Client
(
stub
)
# Initiate authentication, return boolean specifying whether OK or not
return
c
.
start
(
self
.
_username
,
self
.
_password
)
def
testConnection
(
self
,
conn
):
def
testConnection
(
self
,
conn
):
"""Internal: test the given connection.
"""Internal: test the given connection.
...
@@ -372,6 +415,12 @@ class ClientStorage:
...
@@ -372,6 +415,12 @@ class ClientStorage:
# XXX Check the protocol version here?
# XXX Check the protocol version here?
self
.
_conn_is_read_only
=
0
self
.
_conn_is_read_only
=
0
stub
=
self
.
StorageServerStubClass
(
conn
)
stub
=
self
.
StorageServerStubClass
(
conn
)
# XXX: Verify return value
auth
=
stub
.
getAuthProtocol
()
if
auth
and
not
self
.
doAuth
(
auth
,
stub
):
raise
AuthError
,
"Authentication failed"
try
:
try
:
stub
.
register
(
str
(
self
.
_storage
),
self
.
_is_read_only
)
stub
.
register
(
str
(
self
.
_storage
),
self
.
_is_read_only
)
return
1
return
1
...
...
src/ZEO/Exceptions.py
View file @
20319afd
...
@@ -24,3 +24,5 @@ class UnrecognizedResult(ClientStorageError):
...
@@ -24,3 +24,5 @@ class UnrecognizedResult(ClientStorageError):
class
ClientDisconnected
(
ClientStorageError
):
class
ClientDisconnected
(
ClientStorageError
):
"""The database storage is disconnected from the storage."""
"""The database storage is disconnected from the storage."""
class
AuthError
(
StorageError
):
"""The client provided invalid authentication credentials."""
src/ZEO/ServerStub.py
View file @
20319afd
##############################################################################
##############################################################################
#
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# Copyright (c) 2001, 2002
, 2003
Zope Corporation and Contributors.
# All Rights Reserved.
# All Rights Reserved.
#
#
# This software is subject to the provisions of the Zope Public License,
# This software is subject to the provisions of the Zope Public License,
...
@@ -45,6 +45,9 @@ class StorageServer:
...
@@ -45,6 +45,9 @@ class StorageServer:
def
get_info
(
self
):
def
get_info
(
self
):
return
self
.
rpc
.
call
(
'get_info'
)
return
self
.
rpc
.
call
(
'get_info'
)
def
getAuthProtocol
(
self
):
return
self
.
rpc
.
call
(
'getAuthProtocol'
)
def
lastTransaction
(
self
):
def
lastTransaction
(
self
):
# Not in protocol version 2.0.0; see __init__()
# Not in protocol version 2.0.0; see __init__()
return
self
.
rpc
.
call
(
'lastTransaction'
)
return
self
.
rpc
.
call
(
'lastTransaction'
)
...
...
src/ZEO/StorageServer.py
View file @
20319afd
##############################################################################
##############################################################################
#
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# Copyright (c) 2001, 2002
, 2003
Zope Corporation and Contributors.
# All Rights Reserved.
# All Rights Reserved.
#
#
# This software is subject to the provisions of the Zope Public License,
# This software is subject to the provisions of the Zope Public License,
...
@@ -31,6 +31,7 @@ import time
...
@@ -31,6 +31,7 @@ import time
from
ZEO
import
ClientStub
from
ZEO
import
ClientStub
from
ZEO.CommitLog
import
CommitLog
from
ZEO.CommitLog
import
CommitLog
from
ZEO.auth.database
import
Database
from
ZEO.monitor
import
StorageStats
,
StatsServer
from
ZEO.monitor
import
StorageStats
,
StatsServer
from
ZEO.zrpc.server
import
Dispatcher
from
ZEO.zrpc.server
import
Dispatcher
from
ZEO.zrpc.connection
import
ManagedServerConnection
,
Delay
,
MTDelay
from
ZEO.zrpc.connection
import
ManagedServerConnection
,
Delay
,
MTDelay
...
@@ -161,6 +162,8 @@ class ZEOStorage:
...
@@ -161,6 +162,8 @@ class ZEOStorage:
"""Select the storage that this client will use
"""Select the storage that this client will use
This method must be the first one called by the client.
This method must be the first one called by the client.
For authenticated storages this method will be called by the client
immediately after authentication is finished.
"""
"""
if
self
.
storage
is
not
None
:
if
self
.
storage
is
not
None
:
self
.
log
(
"duplicate register() call"
)
self
.
log
(
"duplicate register() call"
)
...
@@ -410,6 +413,15 @@ class ZEOStorage:
...
@@ -410,6 +413,15 @@ class ZEOStorage:
else
:
else
:
return
self
.
_wait
(
lambda
:
self
.
_vote
())
return
self
.
_wait
(
lambda
:
self
.
_vote
())
def
getAuthProtocol
(
self
):
"""Return string specifying name of authentication module to use.
The module name should be auth_%s where %s is auth_protocol."""
protocol
=
self
.
server
.
auth_protocol
if
not
protocol
or
protocol
==
'none'
:
return
None
return
protocol
def
abortVersion
(
self
,
src
,
id
):
def
abortVersion
(
self
,
src
,
id
):
self
.
_check_tid
(
id
,
exc
=
StorageTransactionError
)
self
.
_check_tid
(
id
,
exc
=
StorageTransactionError
)
if
self
.
locked
:
if
self
.
locked
:
...
@@ -577,7 +589,9 @@ class StorageServer:
...
@@ -577,7 +589,9 @@ class StorageServer:
def
__init__
(
self
,
addr
,
storages
,
read_only
=
0
,
def
__init__
(
self
,
addr
,
storages
,
read_only
=
0
,
invalidation_queue_size
=
100
,
invalidation_queue_size
=
100
,
transaction_timeout
=
None
,
transaction_timeout
=
None
,
monitor_address
=
None
):
monitor_address
=
None
,
auth_protocol
=
None
,
auth_filename
=
None
):
"""StorageServer constructor.
"""StorageServer constructor.
This is typically invoked from the start.py script.
This is typically invoked from the start.py script.
...
@@ -618,7 +632,22 @@ class StorageServer:
...
@@ -618,7 +632,22 @@ class StorageServer:
monitor_address -- The address at which the monitor server
monitor_address -- The address at which the monitor server
should listen. If specified, a monitor server is started.
should listen. If specified, a monitor server is started.
The monitor server provides server statistics in a simple
The monitor server provides server statistics in a simple
text format.
text format.
auth_protocol -- The name of the authentication protocol to use.
Examples are "plaintext", "sha" and "srp".
auth_filename -- The name of the password database filename.
It should be in a format compatible with the authentication
protocol used; for instance, "sha" and "srp" require different
formats.
Note that to implement an authentication protocol, a server
and client authentication mechanism must be implemented in a
auth_* module, which should be stored inside the "auth"
subdirectory. This module may also define a DatabaseClass
variable that should indicate what database should be used
by the authenticator.
"""
"""
self
.
addr
=
addr
self
.
addr
=
addr
...
@@ -633,6 +662,10 @@ class StorageServer:
...
@@ -633,6 +662,10 @@ class StorageServer:
for
s
in
storages
.
values
():
for
s
in
storages
.
values
():
s
.
_waiting
=
[]
s
.
_waiting
=
[]
self
.
read_only
=
read_only
self
.
read_only
=
read_only
self
.
auth_protocol
=
auth_protocol
self
.
auth_filename
=
auth_filename
if
auth_protocol
:
self
.
_setup_auth
(
auth_protocol
)
# A list of at most invalidation_queue_size invalidations
# A list of at most invalidation_queue_size invalidations
self
.
invq
=
[]
self
.
invq
=
[]
self
.
invq_bound
=
invalidation_queue_size
self
.
invq_bound
=
invalidation_queue_size
...
@@ -654,7 +687,43 @@ class StorageServer:
...
@@ -654,7 +687,43 @@ class StorageServer:
self
.
monitor
=
StatsServer
(
monitor_address
,
self
.
stats
)
self
.
monitor
=
StatsServer
(
monitor_address
,
self
.
stats
)
else
:
else
:
self
.
monitor
=
None
self
.
monitor
=
None
def
_setup_auth
(
self
,
protocol
):
# Load the auth protocol
fullname
=
'ZEO.auth.auth_'
+
protocol
try
:
module
=
__import__
(
fullname
,
globals
(),
locals
(),
protocol
)
except
ImportError
:
log
(
"%s: no such an auth protocol: %s"
%
(
self
.
__class__
.
__name__
,
protocol
))
self
.
auth_protocol
=
None
return
from
ZEO.auth.storage
import
AuthZEOStorage
# And set up ZEOStorageClass
klass
=
getattr
(
module
,
'StorageClass'
,
None
)
if
not
klass
or
not
issubclass
(
klass
,
AuthZEOStorage
):
log
((
"%s: %s is not a valid auth protocol, must have a "
+
\
"StorageClass class"
)
%
(
self
.
__class__
.
__name__
,
protocol
))
self
.
auth_protocol
=
None
return
self
.
ZEOStorageClass
=
klass
log
(
"%s: using auth protocol: %s"
%
\
(
self
.
__class__
.
__name__
,
protocol
))
dbklass
=
getattr
(
module
,
'DatabaseClass'
,
None
)
if
not
dbklass
:
dbklass
=
Database
# We create a Database instance here for use with the authenticator
# modules. Having one instance allows it to be shared between multiple
# storages, avoiding the need to bloat each with a new authenticator
# Database that would contain the same info, and also avoiding any
# possibly synchronization issues between them.
self
.
database
=
dbklass
(
self
.
auth_filename
)
def
new_connection
(
self
,
sock
,
addr
):
def
new_connection
(
self
,
sock
,
addr
):
"""Internal: factory to create a new connection.
"""Internal: factory to create a new connection.
...
@@ -663,6 +732,8 @@ class StorageServer:
...
@@ -663,6 +732,8 @@ class StorageServer:
connection.
connection.
"""
"""
z
=
self
.
ZEOStorageClass
(
self
,
self
.
read_only
)
z
=
self
.
ZEOStorageClass
(
self
,
self
.
read_only
)
if
self
.
auth_protocol
:
z
.
set_database
(
self
.
database
)
c
=
self
.
ManagedServerConnectionClass
(
sock
,
addr
,
z
,
self
)
c
=
self
.
ManagedServerConnectionClass
(
sock
,
addr
,
z
,
self
)
log
(
"new connection %s: %s"
%
(
addr
,
`c`
))
log
(
"new connection %s: %s"
%
(
addr
,
`c`
))
return
c
return
c
...
...
src/ZEO/runzeo.py
View file @
20319afd
#!python
#!python
##############################################################################
##############################################################################
#
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# Copyright (c) 2001, 2002
, 2003
Zope Corporation and Contributors.
# All Rights Reserved.
# All Rights Reserved.
#
#
# This software is subject to the provisions of the Zope Public License,
# This software is subject to the provisions of the Zope Public License,
...
@@ -89,7 +89,9 @@ class ZEOOptionsMixin:
...
@@ -89,7 +89,9 @@ class ZEOOptionsMixin:
"t:"
,
"timeout="
,
float
)
"t:"
,
"timeout="
,
float
)
self
.
add
(
"monitor_address"
,
"zeo.monitor_address"
,
"m:"
,
"monitor="
,
self
.
add
(
"monitor_address"
,
"zeo.monitor_address"
,
"m:"
,
"monitor="
,
self
.
handle_monitor_address
)
self
.
handle_monitor_address
)
self
.
add
(
'auth_protocol'
,
'zeo.auth_protocol'
,
None
,
'auth-protocol='
,
default
=
None
)
self
.
add
(
'auth_filename'
,
'zeo.auth_filename'
,
None
,
'auth-filename='
)
class
ZEOOptions
(
ZDOptions
,
ZEOOptionsMixin
):
class
ZEOOptions
(
ZDOptions
,
ZEOOptionsMixin
):
...
@@ -189,7 +191,9 @@ class ZEOServer:
...
@@ -189,7 +191,9 @@ class ZEOServer:
read_only
=
self
.
options
.
read_only
,
read_only
=
self
.
options
.
read_only
,
invalidation_queue_size
=
self
.
options
.
invalidation_queue_size
,
invalidation_queue_size
=
self
.
options
.
invalidation_queue_size
,
transaction_timeout
=
self
.
options
.
transaction_timeout
,
transaction_timeout
=
self
.
options
.
transaction_timeout
,
monitor_address
=
self
.
options
.
monitor_address
)
monitor_address
=
self
.
options
.
monitor_address
,
auth_protocol
=
self
.
options
.
auth_protocol
,
auth_filename
=
self
.
options
.
auth_filename
)
def
loop_forever
(
self
):
def
loop_forever
(
self
):
import
ThreadedAsync.LoopCallback
import
ThreadedAsync.LoopCallback
...
...
src/ZEO/tests/testAuth.py
0 → 100644
View file @
20319afd
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Test suite for AuthZEO."""
import
glob
import
os
import
time
import
unittest
from
ThreadedAsync
import
LoopCallback
from
ZEO.auth.database
import
Database
#from ZEO.auth.auth_srp import SRPDatabase
from
ZEO.ClientStorage
import
ClientStorage
from
ZEO.StorageServer
import
StorageServer
from
ZODB.FileStorage
import
FileStorage
storage
=
FileStorage
(
'auth-test.fs'
)
SOCKET
=
'auth-test-socket'
STORAGES
=
{
'1'
:
storage
}
class
BaseTest
(
unittest
.
TestCase
):
def
createDB
(
self
,
name
):
if
os
.
path
.
exists
(
name
):
os
.
remove
(
self
.
database
)
if
name
.
endswith
(
'srp'
):
db
=
SRPDatabase
(
name
)
else
:
db
=
Database
(
name
)
db
.
add_user
(
'foo'
,
'bar'
)
db
.
save
()
def
setUp
(
self
):
self
.
createDB
(
self
.
database
)
self
.
pid
=
os
.
fork
()
if
not
self
.
pid
:
self
.
server
=
StorageServer
(
SOCKET
,
STORAGES
,
auth_protocol
=
self
.
protocol
,
auth_filename
=
self
.
database
)
LoopCallback
.
loop
()
def
tearDown
(
self
):
os
.
kill
(
self
.
pid
,
9
)
os
.
remove
(
self
.
database
)
os
.
remove
(
SOCKET
)
for
file
in
glob
.
glob
(
'auth-test.fs*'
):
os
.
remove
(
file
)
def
check
(
self
):
# Sleep for 0.2 seconds to give the server some time to start up
# seems to be needed before and after creating the storage
time
.
sleep
(
0.2
)
cs
=
ClientStorage
(
SOCKET
,
wait
=
0
,
username
=
'foo'
,
password
=
'bar'
)
time
.
sleep
(
0.2
)
if
cs
.
_connection
==
None
:
raise
AssertionError
,
\
"authentication for %s failed"
%
self
.
protocol
cs
.
_connection
.
poll
()
if
not
cs
.
is_connected
():
raise
AssertionError
,
\
"authentication for %s failed"
%
self
.
protocol
class
PlainTextAuth
(
BaseTest
):
protocol
=
'plaintext'
database
=
'authdb.sha'
class
SHAAuth
(
BaseTest
):
protocol
=
'sha'
database
=
'authdb.sha'
#class SRPAuth(BaseTest):
# protocol = 'srp'
# database = 'authdb.srp'
test_classes
=
[
PlainTextAuth
,
SHAAuth
]
# SRPAuth
def
test_suite
():
suite
=
unittest
.
TestSuite
()
for
klass
in
test_classes
:
sub
=
unittest
.
makeSuite
(
klass
,
'check'
)
suite
.
addTest
(
sub
)
return
suite
if
__name__
==
"__main__"
:
unittest
.
main
(
defaultTest
=
'test_suite'
)
src/ZEO/zpasswd.py
0 → 100644
View file @
20319afd
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Usage:
zpasswd [-cd] passwordfile username
zpasswd -b[cd] passwordfile username password
zpasswd -n[d] username
zpasswd -nb[d] username password
-c Create a new file.
-d Delete user
-n Don't update file; display results on stdout.
-b Use the password from the command line rather than prompting for it."""
import
sys
import
getopt
import
getpass
from
ZEO.auth.database
import
Database
#from ZEO.auth.srp import SRPDatabase
try
:
opts
,
args
=
getopt
.
getopt
(
sys
.
argv
[
1
:],
'cdnbs'
)
except
getopt
.
GetoptError
:
# print help information and exit:
print
__doc__
sys
.
exit
(
2
)
stdout
=
0
create
=
0
delete
=
0
prompt
=
1
#srp = 0
for
opt
,
arg
in
opts
:
if
opt
in
(
"-h"
,
"--help"
):
print
__doc__
sys
.
exit
()
if
opt
==
"-n"
:
stdout
=
1
if
opt
==
"-c"
:
create
=
1
if
opt
==
"-d"
:
delete
=
1
if
opt
==
"b"
:
prompt
=
0
# if opt == "-s":
# srp = 1
if
create
and
delete
:
print
"Can't create and delete at the same time"
sys
.
exit
(
3
)
if
len
(
args
)
<
2
:
print
__doc__
sys
.
exit
()
output
=
args
[
0
]
username
=
args
[
1
]
if
not
delete
:
if
len
(
args
)
>
3
:
print
__doc__
sys
.
exit
()
if
prompt
:
password
=
getpass
.
getpass
(
'Enter passphrase: '
)
else
:
password
=
args
[
2
]
#if srp:
# db = SRPDatabase(output)
#else:
db
=
Database
(
output
)
if
create
:
try
:
db
.
add_user
(
username
,
password
)
except
LookupError
:
print
'The username already exists'
sys
.
exit
(
4
)
if
stdout
:
db
.
save
(
fd
=
sys
.
stdout
)
else
:
db
.
save
()
if
delete
:
try
:
db
.
del_user
(
username
)
except
LockupError
:
print
'The username doesn
\
'
t exist'
sys
.
exit
(
5
)
if
stdout
:
db
.
save
(
fd
=
sys
.
stdout
)
else
:
db
.
save
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment