addDescription( 'Generate CDB file of common passwords' ); $this->addOption( 'limit', "Max number of passwords to write", false, true, 'l' ); $this->addArg( 'inputfile', 'List of passwords (one per line) to use or - for stdin', true ); $this->addArg( 'output', "Location to write CDB file to (Try $IP/includes/password/commonpasswords.cdb)", true ); } public function execute() { $limit = (int)$this->getOption( 'limit', PHP_INT_MAX ); $langEn = Language::factory( 'en' ); $infile = $this->getArg( 0 ); if ( $infile === '-' ) { $infile = 'php://stdin'; } $outfile = $this->getArg( 1 ); if ( !is_readable( $infile ) && $infile !== 'php://stdin' ) { $this->fatalError( "Cannot open input file $infile for reading" ); } $file = fopen( $infile, 'r' ); if ( $file === false ) { $this->fatalError( "Cannot read input file $infile" ); } try { $db = \Cdb\Writer::open( $outfile ); $alreadyWritten = []; $skipped = 0; for ( $i = 0; ( $i - $skipped ) < $limit; $i++ ) { if ( feof( $file ) ) { break; } $rawLine = fgets( $file ); if ( $rawLine === false ) { $this->error( "Error reading input file" ); break; } if ( substr( $rawLine, -1 ) !== "\n" && !feof( $file ) ) { // We're assuming that this just won't happen. $this->error( "fgets did not return whole line at $i??" ); } $line = $langEn->lc( trim( $rawLine ) ); if ( $line === '' ) { $this->error( "Line number " . ( $i + 1 ) . " is blank?" ); $skipped++; continue; } if ( isset( $alreadyWritten[$line] ) ) { $this->output( "Password '$line' already written (line " . ( $i + 1 ) . ")\n" ); $skipped++; continue; } $alreadyWritten[$line] = true; $db->set( $line, $i + 1 - $skipped ); } // All caps, so cannot conflict with potential password $db->set( '_TOTALENTRIES', $i - $skipped ); $db->close(); $this->output( "Successfully wrote " . ( $i - $skipped ) . " (out of $i) passwords to $outfile\n" ); } catch ( \Cdb\Exception $e ) { $this->fatalError( "Error writing cdb file: " . $e->getMessage(), 2 ); } } } $maintClass = CreateCommonPasswordCdb::class; require_once RUN_MAINTENANCE_IF_MAIN;