タグ: ruby

ChatGPTによるRubyスクリプト。(パスワード生成スクリプト)

ChatGPTを利用するようになってから、「こういう処理ができたら仕事の処理が楽になるのに」が現実的になりました。

概要

割と設定する機会があるパスワード。

  • キチッとランダムに
  • 桁数や出力数が指定可能で
  • ファイルに出力する必要があるか
  • または標準出力に表示させればいいのか

を設定するRubyスクリプトはできないものかとChatGPTにお伺い。幾度かの対話を繰り返し、ようやく想定通りの動きをするスクリプトができました。

openssl rand と異なり、

  • 大文字/小文字の利用
  • 数字や記号の混在

を細かく設定できるのがポイントです。

生成・編集したスクリプト

  • スクリプト名:password_generate.rb

前提

以下の環境で動作を確認しました。

  • Ubuntu 20.04 LTS
  • CentOS 7
  • Ruby 2.4 / 2.7.0

スクリプト内容

  • password_generate.rb
#このRubyスクリプトは、SecureRandomモジュールを使用してランダムなパスワードを生成するためのスクリプトです。
#パスワードの生成に関する様々な設定を変数で行うことができます。
#例えば、パスワードの長さ、数字やアルファベット、大文字や記号を使用するかどうかなどを指定することができます。
#スクリプトは、出力先がファイルか標準出力かを選択できます。
#ファイルに出力する場合は出力先のディレクトリやファイル名を指定することができます。

# モジュールを呼び出します 
require 'securerandom'
require 'fileutils'
require 'date'

### 変数はここからです
## 出力するパスワードの数(行数)を数字で指定します
num_passwords = 12
## 出力先を選択します
# ファイルに出力する場合は 1、標準出力に出力する場合は 0 に設定します
output_to_file = 1
# 出力先のディレクトリを指定します
output_directory = '/home/hoge/restore_password' 
# 出力ファイル名を名前+yyyymmdd形式.txtで指定します
# 最初の''部分の名前を任意の名前に入力ください
output_filename =  'mysql-restore.' + Time.now.strftime("%Y%m%d") + '.txt'
## パスワードの強度を指定します
# パスワード桁数を数字で指定します
password_length = 10
# 数字を用いる場合は1を、用いない場合は0を指定します
use_numbers = 1
# アルファベット小文字を用いる場合は1を、用いない場合は0を指定します
use_alphabet = 1
# アルファベット大文字を用いる場合は1を、用いない場合は0を指定します
use_uppercase = 1
# 記号を用いる場合は1を、用いない場合は0を指定します
use_symbols = 1
## パスワード生成用の文字種を定義します
# 必要に応じて使わない文字を削除することが可能です(lと|, 0とOなど)
characters = ''
characters += '0123456789' if use_numbers == 1
characters += 'abcdefghijklmnopqrstuvwxyz' if use_alphabet == 1
characters += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' if use_uppercase == 1
characters += '!#$%&()*+,-./:;<=>?@[]^_`{|}~' if use_symbols == 1
### 変数はここまでです

# パスワード生成関数を定義します
def generate_password(length, characters)
  SecureRandom.random_bytes(length).unpack('C*').map do |byte|
    characters[byte % characters.length]
  end.join
end

## パスワードファイルを出力する場合(変数 output_to_fileを1にしたとき)の処理です
#出力先のパスを作成します
if output_to_file == 1
  output_path = File.join(output_directory, output_filename)
# 出力先のディレクトリが存在しない場合は作成します
  FileUtils.mkdir_p(output_directory)
# パスワードを出力します
  File.open(output_path, 'w') do |file|
    num_passwords.times do
      password = generate_password(password_length, characters)
      file.puts password
    end
  end
else

## 標準出力に出すだけの場合(変数 output_to_fileを0にしたとき)の処理です
# パスワードを標準出力に出力します
  num_passwords.times do
    password = generate_password(password_length, characters)
    puts password
  end
end

使い方

  1. 変数を環境に合わせて定義します。
  2. ruby password_genarate.rbを実行します。
  3. 定義したとおりパスワードファイルが出力されていたり、画面に表示されれば成功です。

今後の展望

  • 他のスクリプトで呼び出す(以前に紹介したMySQLバックアップ時にパスワードをかけるなど
  • 対話式で実行

など、使い勝手に合わせて修正していきたいです。

ChatGPTによるスクリプト変換。(bash → Ruby)

ことのあらまし

手なりで作ったシェルスクリプトを発展させたり可読性を高めるために利用しているChatGPT。

考えを発展させて「スクリプトの変換はできるのではないか」と考えました。

元となったスクリプト

こちらにある

cat error.log | awk 'match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/) { print  substr($0, RSTART, RLENGTH) }' | sort | uniq > /var/lib/redmine/log/suspicious_ip/suspicious_ip.`date +%Y%m%d`
  • error.logを読み込み
  • IPアドレスにマッチする正規表現を取り出し
  • ソートした上で重複を排除
  • 指定のディレクトリに書き出す

という一文のシェルスクリプトをRubyで動かすにはとChatGPTに質問しました。

出来上がったRubyスクリプト

require 'date'

## 変数指定ここから
# error.log の格納ディレクトリ
log_dir = '/path/to/log_dir'
# error.log の名前
log_file = 'error.log'
# 別ファイルの出力ディレクトリ
output_dir = '/path/to/output_dir'
# 重複を排除する場合は 1、しない場合は 0 を指定
remove_duplicates = 1
# 別ファイルの名前
output_file = 'output.txt'
# IPアドレスを抜き出すための正規表現パターン
ip_regex = /client (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/
# error.log ファイルのフルパス
log_path = File.join(log_dir, log_file)
## 変数指定ここまで

# error.log ファイルを開く
File.open(log_path) do |file|
  # IPアドレスのみを格納する配列
  ips = []

  # 各行をチェックする
  file.each_line do |line|
    # 正規表現パターンに一致するか確認する
    match = line.match(ip_regex)
    if match
      # 一致した場合、IPアドレスを配列に格納する
      ips << match[1]
    end
  end

  # 重複を排除する場合
  if remove_duplicates == 1
    ips.uniq!
  end

  # 昇順にソートする
  ips.sort!

  # 結果を出力するファイルのパス
  output_path = File.join(output_dir, "error_#{Date.today.strftime('%Y%m%d')}_#{output_file}")

  # 結果を出力する
  File.open(output_path, 'w') do |file|
    ips.each do |ip|
      file.puts ip
    end
  end
end

スクリプトは長くなりましたが、以下の利点があります。

  • 読み込むディレクトリや正規表現のパターンを変数化しているため、他のログにも転用可能
  • 重複を排除するかしないかを決められる

また、可読性も高くなっています。

何より、シェルスクリプトの動きをRubyで動かすための文法を学べるのも素晴らしく。

今後の作業の大きな力になります。

Ubuntu 22.04系にRuby2.7をインストール

結論から言えば、Ubuntu 22.04系は普通にやったのではRuby 2.7はインストールできません。

なぜならRuby 2.7が必要とするOpenssl1.1.1系をUbuntu 22.04系がサポートしていないからです。

そんな中で、どうしてもこのバージョンを入れたいというケースがあったので対応を行いました。

手順

参考
https://github.com/rbenv/ruby-build/discussions/1940#discussioncomment-2663209

依存関係をインストールします。

sudo apt install git build-essential checkinstall zlib1g-dev

rbenvをインストールします。

git clone https://github.com/rbenv/rbenv.git ~/.rbenv
rbenvのパスを通します。
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc

source ~/.bashrc

ruby-buildをインストールします。

git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build

OpenSSL 1.1.1をインストールします。

cd ~/Downloads
wget https://www.openssl.org/source/openssl-1.1.1q.tar.gz
tar xf openssl-1.1.1q.tar.gz

cd ~/Downloads/openssl-1.1.1q
./config --prefix=/opt/openssl-1.1.1q --openssldir=/opt/openssl-1.1.1q shared zlib
make
make test
sudo make install

シンボリックリンクを張り替えます。

sudo rm -rf /opt/openssl-1.1.1q/certs
sudo ln -s /etc/ssl/certs /opt/openssl-1.1.1q

ruby 2.7系をインストールします。

RUBY_CONFIGURE_OPTS=--with-openssl-dir=/opt/openssl-1.1.1q
RUBY_CONFIGURE_OPTS=--with-openssl-dir=/opt/openssl-1.1.1q rbenv install 2.7.6

rbenv global 2.7.6

インストールされていることを確認します。

ruby -v
ruby 2.7.6p219 (2022-04-12 revision c9c2245c0a) [x86_64-linux]

rootが参照できるようにパスを通します。

which ruby
# /home/user1/.rbenv/shims
# 結果を控えておきます
sudo su -

# ↓以下、rootでの作業↓
echo "export PATH=$PATH:/home/user1/.rbenv/shims" >> ~/.bashrc
source ~/.bashrc
which ruby
# /home/user1/.rbenv/shims
# 控えておいたパスであることを確認します
ruby -v
# ruby 2.7.6p219 (2022-04-12 revision c9c2245c0a) [x86_64-linux]
# 2.7系であることを確認します

と、ここまで書きましたがきっとDockerなどのコンテナを使ったほうが楽かと思います。

Page 2 of 2

Powered by WordPress & Theme by Anders Norén