2021-11-23 09:45:38 +00:00
package commands
import (
2022-06-14 12:40:00 +00:00
"fmt"
"strings"
2021-11-23 09:45:38 +00:00
"github.com/spf13/cobra"
2022-04-07 23:01:01 +00:00
"github.com/authelia/authelia/v4/internal/configuration/schema"
2021-11-23 09:45:38 +00:00
)
2022-06-14 12:40:00 +00:00
func newStorageCmd ( ) ( cmd * cobra . Command ) {
2021-11-23 09:45:38 +00:00
cmd = & cobra . Command {
Use : "storage" ,
2022-06-14 12:40:00 +00:00
Short : cmdAutheliaStorageShort ,
Long : cmdAutheliaStorageLong ,
Example : cmdAutheliaStorageExample ,
2021-11-23 09:45:38 +00:00
Args : cobra . NoArgs ,
PersistentPreRunE : storagePersistentPreRunE ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2021-11-23 09:45:38 +00:00
}
2022-03-04 03:39:22 +00:00
cmdWithConfigFlags ( cmd , true , [ ] string { "configuration.yml" } )
2021-11-23 09:45:38 +00:00
2022-11-25 12:44:55 +00:00
cmd . PersistentFlags ( ) . String ( cmdFlagNameEncryptionKey , "" , "the storage encryption key to use" )
cmd . PersistentFlags ( ) . String ( cmdFlagNameSQLite3Path , "" , "the SQLite database path" )
cmd . PersistentFlags ( ) . String ( cmdFlagNameMySQLHost , "" , "the MySQL hostname" )
cmd . PersistentFlags ( ) . Int ( cmdFlagNameMySQLPort , 3306 , "the MySQL port" )
cmd . PersistentFlags ( ) . String ( cmdFlagNameMySQLDatabase , "authelia" , "the MySQL database name" )
cmd . PersistentFlags ( ) . String ( cmdFlagNameMySQLUsername , "authelia" , "the MySQL username" )
cmd . PersistentFlags ( ) . String ( cmdFlagNameMySQLPassword , "" , "the MySQL password" )
cmd . PersistentFlags ( ) . String ( cmdFlagNamePostgreSQLHost , "" , "the PostgreSQL hostname" )
cmd . PersistentFlags ( ) . Int ( cmdFlagNamePostgreSQLPort , 5432 , "the PostgreSQL port" )
cmd . PersistentFlags ( ) . String ( cmdFlagNamePostgreSQLDatabase , "authelia" , "the PostgreSQL database name" )
cmd . PersistentFlags ( ) . String ( cmdFlagNamePostgreSQLSchema , "public" , "the PostgreSQL schema name" )
cmd . PersistentFlags ( ) . String ( cmdFlagNamePostgreSQLUsername , "authelia" , "the PostgreSQL username" )
cmd . PersistentFlags ( ) . String ( cmdFlagNamePostgreSQLPassword , "" , "the PostgreSQL password" )
2021-12-02 05:36:03 +00:00
cmd . PersistentFlags ( ) . String ( "postgres.ssl.mode" , "disable" , "the PostgreSQL ssl mode" )
cmd . PersistentFlags ( ) . String ( "postgres.ssl.root_certificate" , "" , "the PostgreSQL ssl root certificate file location" )
cmd . PersistentFlags ( ) . String ( "postgres.ssl.certificate" , "" , "the PostgreSQL ssl certificate file location" )
cmd . PersistentFlags ( ) . String ( "postgres.ssl.key" , "" , "the PostgreSQL ssl key file location" )
2021-11-23 09:45:38 +00:00
cmd . AddCommand (
newStorageMigrateCmd ( ) ,
newStorageSchemaInfoCmd ( ) ,
2021-11-25 01:56:58 +00:00
newStorageEncryptionCmd ( ) ,
2022-04-09 07:13:19 +00:00
newStorageUserCmd ( ) ,
)
return cmd
}
2022-06-14 12:40:00 +00:00
func newStorageEncryptionCmd ( ) ( cmd * cobra . Command ) {
2022-04-09 07:13:19 +00:00
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "encryption" ,
Short : cmdAutheliaStorageEncryptionShort ,
Long : cmdAutheliaStorageEncryptionLong ,
Example : cmdAutheliaStorageEncryptionExample ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2022-04-09 07:13:19 +00:00
}
cmd . AddCommand (
2022-06-14 12:40:00 +00:00
newStorageEncryptionChangeKeyCmd ( ) ,
newStorageEncryptionCheckCmd ( ) ,
2021-11-25 01:56:58 +00:00
)
return cmd
}
2022-06-14 12:40:00 +00:00
func newStorageEncryptionCheckCmd ( ) ( cmd * cobra . Command ) {
2022-04-09 07:13:19 +00:00
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "check" ,
Short : cmdAutheliaStorageEncryptionCheckShort ,
Long : cmdAutheliaStorageEncryptionCheckLong ,
Example : cmdAutheliaStorageEncryptionCheckExample ,
RunE : storageSchemaEncryptionCheckRunE ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2022-04-09 07:13:19 +00:00
}
2022-11-25 12:44:55 +00:00
cmd . Flags ( ) . Bool ( cmdFlagNameVerbose , false , "enables verbose checking of every row of encrypted data" )
2022-04-09 07:13:19 +00:00
return cmd
}
2022-06-14 12:40:00 +00:00
func newStorageEncryptionChangeKeyCmd ( ) ( cmd * cobra . Command ) {
2022-04-09 07:13:19 +00:00
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "change-key" ,
Short : cmdAutheliaStorageEncryptionChangeKeyShort ,
Long : cmdAutheliaStorageEncryptionChangeKeyLong ,
Example : cmdAutheliaStorageEncryptionChangeKeyExample ,
RunE : storageSchemaEncryptionChangeKeyRunE ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2022-04-09 07:13:19 +00:00
}
2022-11-25 12:44:55 +00:00
cmd . Flags ( ) . String ( cmdFlagNameNewEncryptionKey , "" , "the new key to encrypt the data with" )
2022-04-09 07:13:19 +00:00
return cmd
}
2022-06-14 12:40:00 +00:00
func newStorageUserCmd ( ) ( cmd * cobra . Command ) {
2022-04-09 07:13:19 +00:00
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "user" ,
Short : cmdAutheliaStorageUserShort ,
Long : cmdAutheliaStorageUserLong ,
Example : cmdAutheliaStorageUserExample ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2022-04-09 07:13:19 +00:00
}
2022-06-14 12:40:00 +00:00
cmd . AddCommand (
newStorageUserIdentifiersCmd ( ) ,
newStorageUserTOTPCmd ( ) ,
2022-10-19 07:17:55 +00:00
newStorageUserWebAuthnCmd ( ) ,
2022-06-14 12:40:00 +00:00
)
2022-04-09 07:13:19 +00:00
return cmd
}
2022-06-14 12:40:00 +00:00
func newStorageUserIdentifiersCmd ( ) ( cmd * cobra . Command ) {
2022-04-25 08:49:18 +00:00
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "identifiers" ,
Short : cmdAutheliaStorageUserIdentifiersShort ,
Long : cmdAutheliaStorageUserIdentifiersLong ,
Example : cmdAutheliaStorageUserIdentifiersExample ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2022-04-25 08:49:18 +00:00
}
2022-06-14 12:40:00 +00:00
cmd . AddCommand (
newStorageUserIdentifiersExportCmd ( ) ,
newStorageUserIdentifiersImportCmd ( ) ,
newStorageUserIdentifiersGenerateCmd ( ) ,
newStorageUserIdentifiersAddCmd ( ) ,
)
2022-04-25 08:49:18 +00:00
return cmd
}
2022-06-14 12:40:00 +00:00
func newStorageUserIdentifiersExportCmd ( ) ( cmd * cobra . Command ) {
2022-04-09 07:13:19 +00:00
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "export" ,
Short : cmdAutheliaStorageUserIdentifiersExportShort ,
Long : cmdAutheliaStorageUserIdentifiersExportLong ,
Example : cmdAutheliaStorageUserIdentifiersExportExample ,
RunE : storageUserIdentifiersExport ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2022-04-09 07:13:19 +00:00
}
2022-11-25 12:44:55 +00:00
cmd . Flags ( ) . StringP ( cmdFlagNameFile , "f" , "user-opaque-identifiers.yml" , "The file name for the YAML export" )
2022-04-09 07:13:19 +00:00
return cmd
}
2022-06-14 12:40:00 +00:00
func newStorageUserIdentifiersImportCmd ( ) ( cmd * cobra . Command ) {
2021-11-25 01:56:58 +00:00
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "import" ,
Short : cmdAutheliaStorageUserIdentifiersImportShort ,
Long : cmdAutheliaStorageUserIdentifiersImportLong ,
Example : cmdAutheliaStorageUserIdentifiersImportExample ,
RunE : storageUserIdentifiersImport ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2021-11-25 01:56:58 +00:00
}
2022-11-25 12:44:55 +00:00
cmd . Flags ( ) . StringP ( cmdFlagNameFile , "f" , "user-opaque-identifiers.yml" , "The file name for the YAML import" )
2021-11-23 09:45:38 +00:00
return cmd
}
2022-06-14 12:40:00 +00:00
func newStorageUserIdentifiersGenerateCmd ( ) ( cmd * cobra . Command ) {
2021-11-25 01:56:58 +00:00
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "generate" ,
Short : cmdAutheliaStorageUserIdentifiersGenerateShort ,
Long : cmdAutheliaStorageUserIdentifiersGenerateLong ,
Example : cmdAutheliaStorageUserIdentifiersGenerateExample ,
RunE : storageUserIdentifiersGenerate ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2021-11-25 01:56:58 +00:00
}
2022-11-25 12:44:55 +00:00
cmd . Flags ( ) . StringSlice ( cmdFlagNameUsers , nil , "The list of users to generate the opaque identifiers for" )
cmd . Flags ( ) . StringSlice ( cmdFlagNameServices , [ ] string { identifierServiceOpenIDConnect } , fmt . Sprintf ( "The list of services to generate the opaque identifiers for, valid values are: %s" , strings . Join ( validIdentifierServices , ", " ) ) )
cmd . Flags ( ) . StringSlice ( cmdFlagNameSectors , [ ] string { "" } , "The list of sectors to generate identifiers for" )
2021-11-25 01:56:58 +00:00
return cmd
}
2022-06-14 12:40:00 +00:00
func newStorageUserIdentifiersAddCmd ( ) ( cmd * cobra . Command ) {
2021-11-25 01:56:58 +00:00
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "add <username>" ,
Short : cmdAutheliaStorageUserIdentifiersAddShort ,
Long : cmdAutheliaStorageUserIdentifiersAddLong ,
Example : cmdAutheliaStorageUserIdentifiersAddExample ,
Args : cobra . ExactArgs ( 1 ) ,
RunE : storageUserIdentifiersAdd ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2021-11-25 01:56:58 +00:00
}
2022-11-25 12:44:55 +00:00
cmd . Flags ( ) . String ( cmdFlagNameIdentifier , "" , "The optional version 4 UUID to use, if not set a random one will be used" )
cmd . Flags ( ) . String ( cmdFlagNameService , identifierServiceOpenIDConnect , fmt . Sprintf ( "The service to add the identifier for, valid values are: %s" , strings . Join ( validIdentifierServices , ", " ) ) )
cmd . Flags ( ) . String ( cmdFlagNameSector , "" , "The sector identifier to use (should usually be blank)" )
2021-11-25 01:56:58 +00:00
return cmd
}
2022-10-19 07:17:55 +00:00
func newStorageUserWebAuthnCmd ( ) ( cmd * cobra . Command ) {
cmd = & cobra . Command {
Use : "webauthn" ,
Short : cmdAutheliaStorageUserWebAuthnShort ,
Long : cmdAutheliaStorageUserWebAuthnLong ,
Example : cmdAutheliaStorageUserWebAuthnExample ,
DisableAutoGenTag : true ,
}
cmd . AddCommand (
newStorageUserWebAuthnListCmd ( ) ,
newStorageUserWebAuthnDeleteCmd ( ) ,
)
return cmd
}
func newStorageUserWebAuthnListCmd ( ) ( cmd * cobra . Command ) {
cmd = & cobra . Command {
Use : "list [username]" ,
Short : cmdAutheliaStorageUserWebAuthnListShort ,
Long : cmdAutheliaStorageUserWebAuthnListLong ,
Example : cmdAutheliaStorageUserWebAuthnListExample ,
RunE : storageWebAuthnListRunE ,
Args : cobra . MaximumNArgs ( 1 ) ,
DisableAutoGenTag : true ,
}
return cmd
}
func newStorageUserWebAuthnDeleteCmd ( ) ( cmd * cobra . Command ) {
cmd = & cobra . Command {
Use : "delete [username]" ,
Short : cmdAutheliaStorageUserWebAuthnDeleteShort ,
Long : cmdAutheliaStorageUserWebAuthnDeleteLong ,
Example : cmdAutheliaStorageUserWebAuthnDeleteExample ,
RunE : storageWebAuthnDeleteRunE ,
Args : cobra . MaximumNArgs ( 1 ) ,
DisableAutoGenTag : true ,
}
2022-11-25 12:44:55 +00:00
cmd . Flags ( ) . Bool ( cmdFlagNameAll , false , "delete all of the users webauthn devices" )
cmd . Flags ( ) . String ( cmdFlagNameDescription , "" , "delete a users webauthn device by description" )
cmd . Flags ( ) . String ( cmdFlagNameKeyID , "" , "delete a users webauthn device by key id" )
2022-10-19 07:17:55 +00:00
return cmd
}
2022-06-14 12:40:00 +00:00
func newStorageUserTOTPCmd ( ) ( cmd * cobra . Command ) {
2021-11-25 01:56:58 +00:00
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "totp" ,
Short : cmdAutheliaStorageUserTOTPShort ,
Long : cmdAutheliaStorageUserTOTPLong ,
Example : cmdAutheliaStorageUserTOTPExample ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2021-11-25 01:56:58 +00:00
}
2021-12-01 12:11:29 +00:00
cmd . AddCommand (
2022-06-14 12:40:00 +00:00
newStorageUserTOTPGenerateCmd ( ) ,
newStorageUserTOTPDeleteCmd ( ) ,
newStorageUserTOTPExportCmd ( ) ,
2021-12-01 12:11:29 +00:00
)
2021-11-25 01:56:58 +00:00
return cmd
}
2022-06-14 12:40:00 +00:00
func newStorageUserTOTPGenerateCmd ( ) ( cmd * cobra . Command ) {
2021-11-25 01:56:58 +00:00
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "generate <username>" ,
Short : cmdAutheliaStorageUserTOTPGenerateShort ,
Long : cmdAutheliaStorageUserTOTPGenerateLong ,
Example : cmdAutheliaStorageUserTOTPGenerateExample ,
RunE : storageTOTPGenerateRunE ,
Args : cobra . ExactArgs ( 1 ) ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2021-12-01 12:11:29 +00:00
}
2022-11-25 12:44:55 +00:00
cmd . Flags ( ) . String ( cmdFlagNameSecret , "" , "set the shared secret as base32 encoded bytes (no padding), it's recommended that you do not use this option unless you're restoring a configuration" )
cmd . Flags ( ) . Uint ( cmdFlagNameSecretSize , schema . TOTPSecretSizeDefault , "set the secret size" )
cmd . Flags ( ) . Uint ( cmdFlagNamePeriod , 30 , "set the period between rotations" )
cmd . Flags ( ) . Uint ( cmdFlagNameDigits , 6 , "set the number of digits" )
cmd . Flags ( ) . String ( cmdFlagNameAlgorithm , "SHA1" , "set the algorithm to either SHA1 (supported by most applications), SHA256, or SHA512" )
cmd . Flags ( ) . String ( cmdFlagNameIssuer , "Authelia" , "set the issuer description" )
cmd . Flags ( ) . BoolP ( cmdFlagNameForce , "f" , false , "forces the configuration to be generated regardless if it exists or not" )
cmd . Flags ( ) . StringP ( cmdFlagNamePath , "p" , "" , "path to a file to create a PNG file with the QR code (optional)" )
2021-12-01 12:11:29 +00:00
return cmd
}
2022-06-14 12:40:00 +00:00
func newStorageUserTOTPDeleteCmd ( ) ( cmd * cobra . Command ) {
2021-12-01 12:11:29 +00:00
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "delete <username>" ,
Short : cmdAutheliaStorageUserTOTPDeleteShort ,
Long : cmdAutheliaStorageUserTOTPDeleteLong ,
Example : cmdAutheliaStorageUserTOTPDeleteExample ,
RunE : storageTOTPDeleteRunE ,
Args : cobra . ExactArgs ( 1 ) ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2021-12-01 12:11:29 +00:00
}
return cmd
}
2022-06-14 12:40:00 +00:00
func newStorageUserTOTPExportCmd ( ) ( cmd * cobra . Command ) {
2021-12-01 12:11:29 +00:00
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "export" ,
Short : cmdAutheliaStorageUserTOTPExportShort ,
Long : cmdAutheliaStorageUserTOTPExportLong ,
Example : cmdAutheliaStorageUserTOTPExportExample ,
RunE : storageTOTPExportRunE ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2021-11-25 01:56:58 +00:00
}
2022-11-25 12:44:55 +00:00
cmd . Flags ( ) . String ( cmdFlagNameFormat , storageTOTPExportFormatURI , fmt . Sprintf ( "sets the output format, valid values are: %s" , strings . Join ( validStorageTOTPExportFormats , ", " ) ) )
2022-03-02 07:50:36 +00:00
cmd . Flags ( ) . String ( "dir" , "" , "used with the png output format to specify which new directory to save the files in" )
2021-11-25 01:56:58 +00:00
return cmd
}
2021-11-23 09:45:38 +00:00
func newStorageSchemaInfoCmd ( ) ( cmd * cobra . Command ) {
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "schema-info" ,
Short : cmdAutheliaStorageSchemaInfoShort ,
Long : cmdAutheliaStorageSchemaInfoLong ,
Example : cmdAutheliaStorageSchemaInfoExample ,
RunE : storageSchemaInfoRunE ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2021-11-23 09:45:38 +00:00
}
return cmd
}
// NewMigrationCmd returns a new Migration Cmd.
func newStorageMigrateCmd ( ) ( cmd * cobra . Command ) {
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "migrate" ,
Short : cmdAutheliaStorageMigrateShort ,
Long : cmdAutheliaStorageMigrateLong ,
Example : cmdAutheliaStorageMigrateExample ,
Args : cobra . NoArgs ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2021-11-23 09:45:38 +00:00
}
cmd . AddCommand (
newStorageMigrateUpCmd ( ) , newStorageMigrateDownCmd ( ) ,
newStorageMigrateListUpCmd ( ) , newStorageMigrateListDownCmd ( ) ,
newStorageMigrateHistoryCmd ( ) ,
)
return cmd
}
func newStorageMigrateHistoryCmd ( ) ( cmd * cobra . Command ) {
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "history" ,
Short : cmdAutheliaStorageMigrateHistoryShort ,
Long : cmdAutheliaStorageMigrateHistoryLong ,
Example : cmdAutheliaStorageMigrateHistoryExample ,
Args : cobra . NoArgs ,
RunE : storageMigrateHistoryRunE ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2021-11-23 09:45:38 +00:00
}
return cmd
}
func newStorageMigrateListUpCmd ( ) ( cmd * cobra . Command ) {
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "list-up" ,
Short : cmdAutheliaStorageMigrateListUpShort ,
Long : cmdAutheliaStorageMigrateListUpLong ,
Example : cmdAutheliaStorageMigrateListUpExample ,
Args : cobra . NoArgs ,
RunE : newStorageMigrateListRunE ( true ) ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2021-11-23 09:45:38 +00:00
}
return cmd
}
func newStorageMigrateListDownCmd ( ) ( cmd * cobra . Command ) {
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : "list-down" ,
Short : cmdAutheliaStorageMigrateListDownShort ,
Long : cmdAutheliaStorageMigrateListDownLong ,
Example : cmdAutheliaStorageMigrateListDownExample ,
Args : cobra . NoArgs ,
RunE : newStorageMigrateListRunE ( false ) ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2021-11-23 09:45:38 +00:00
}
return cmd
}
func newStorageMigrateUpCmd ( ) ( cmd * cobra . Command ) {
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : storageMigrateDirectionUp ,
Short : cmdAutheliaStorageMigrateUpShort ,
Long : cmdAutheliaStorageMigrateUpLong ,
Example : cmdAutheliaStorageMigrateUpExample ,
Args : cobra . NoArgs ,
RunE : newStorageMigrationRunE ( true ) ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2021-11-23 09:45:38 +00:00
}
2022-11-25 12:44:55 +00:00
cmd . Flags ( ) . IntP ( cmdFlagNameTarget , "t" , 0 , "sets the version to migrate to, by default this is the latest version" )
2021-11-23 09:45:38 +00:00
return cmd
}
func newStorageMigrateDownCmd ( ) ( cmd * cobra . Command ) {
cmd = & cobra . Command {
2022-06-14 12:40:00 +00:00
Use : storageMigrateDirectionDown ,
Short : cmdAutheliaStorageMigrateDownShort ,
Long : cmdAutheliaStorageMigrateDownLong ,
Example : cmdAutheliaStorageMigrateDownExample ,
Args : cobra . NoArgs ,
RunE : newStorageMigrationRunE ( false ) ,
2022-09-01 02:24:47 +00:00
DisableAutoGenTag : true ,
2021-11-23 09:45:38 +00:00
}
2022-11-25 12:44:55 +00:00
cmd . Flags ( ) . IntP ( cmdFlagNameTarget , "t" , 0 , "sets the version to migrate to" )
cmd . Flags ( ) . Bool ( cmdFlagNameDestroyData , false , "confirms you want to destroy data with this migration" )
2021-11-23 09:45:38 +00:00
return cmd
}