Javascriptを使って暗号化と復号化を学ぶ (準備編) 

#JSを使って暗号化と復号化

##きっかけ
webシステムにおける、不正侵入の対策として暗号化と復号化の体験をしたいと考えたため。

「Javascript 暗号化」と調べると、どうやら作れそうなので作ろうと決意。

##構想
メールアドレスとパスワードの入力フォームを作成
（新規登録を想定）

入力されたデータを登録し、暗号化して保存しておくプログラム。

暗号化されたデータを復号化してユーザーに返すプログラム。

##今回作成するプログラム

###1.HTML&CSS
アカウント作成のための入力フォームの作成
レスポンシブにも対応する。

###2.javascript（ユーザー操作部分）
①エンターキーを押して次の入力欄に移動する機能
マウス操作の手間を省くために実装。

しかし、
この後に実装するクリックイベントで
エンター押したときとクリックで押したときの2種類のイベントで作る必要ができた。

②クリックイベント
2つのデータを入力し、送信ボタンでデータを送信する機能
データの取得などの主要な機能は次回の記事に。

###3.javascript（正規表現）
①入力制限
メールアドレスとパスワードの書式を用意し、書式に当てはまらない場合はエラーを出す。

②アラートの表示
入力したデータの内容に応じた、詳細なフォーム検証を行う。

##完成物

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="js,result" data-user="raimumk2" data-slug-hash="qBZNNwx" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="qBZNNwx">
  <span>See the Pen <a href="https://codepen.io/raimumk2/pen/qBZNNwx">
  qBZNNwx</a> by ライム (<a href="https://codepen.io/raimumk2">@raimumk2</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

##サンプルコード
<details><summary>HTML</summary><div>

```html:encryption.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <link rel="stylesheet" href="css/styles.css">

  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
  <div class="web-browser">
    <h1>webブラウザ</h1>
    <form action="#" method="POST" id="create-account" name="create_account">
      <div class="form-label">アカウント作成</div>
      <div class="item">
        <label for="user-id" class="label label1">メールアドレス：</label><input type="email" id="email" class="inputs" name="email">
      </div>
      <div class="item">
        <label for="password" class="label label2">パスワード：</label><input type="password" id="password" class="inputs" name="password"
        >
      </div>
      <div class="item">
        <label for="re-password" class="label label2">パスワード(確認用)：</label><input type="password" id="re-password" class="inputs" name="re-password">
      </div>
      <input type="submit" id="new-create" value="新規登録">
    </form>
  </div>

  <script type="text/javascript" src="js/encryption.js"></script>
</body>
</html>
```

</div></details>

<details><summary>CSS</summary><div>

```css:encryption.css
* {
  margin: 0;
  padding: 0;
}

body {
  color: #300;
}

.web-browser {
  background: #dbedf0;
  padding-bottom: 10px;
}

h1 {
  text-align: center;
  padding-top: 50px;
}

form {
  display: flex;
  flex-direction: column;
  background: #fff;
  width: 500px;
  margin: 40px auto;
  padding: 15px 20px;
}

.form-label {
  
  font-size: 22px;
  text-align: center;
  margin-bottom: 15px;
}

.item {
  overflow: hidden;
  margin-bottom: 15px;
  color: #300;
}

.label {
  float: left;
  height: 33.5px;
  padding-top: 5.5px;
  padding-left: 10px;
}

.label1 {
  margin-right: 65px;
  width: 135px;
  border-left: 3px solid #c00;
}

.label2 {
  margin-right: 20px;
  width: 180px;
  border-left: 3px solid #1760a0;
}

.inputs {
  float: left;
  width: 250px;
}

input[type="email"],
input[type="password"] {
  border: 1px solid #aaa;
  border-radius: 5px;
  padding: 10px;
  font-size: 15px;
}

input[type="submit"] {
  width: 250px;
  background: #80a491;
  border: none;
  color: #fff;
  font-size: 17px;
  font-weight: bold;
  padding: 10px 20px;
  margin: 0 auto;
}

input[type="submit"]:hover {
  opacity: 0.75;
}

@media (max-width: 600px) {
  form {
    padding: 10px 20px;;
  }

  .inputs {
    width: 225px;
  }
}
```

</div></details>

<details><summary>JavaScript</summary><div>

```js:encryption.js
// エンターキーで次の項目に移行する
$('form').on('keydown', 'input', function(e) {
  if (e.keyCode == 13) {
      if ($(this).attr("type") == 'submit') return;

      var form = $(this).closest('form');
      var focusable = form.find('input, button[type="submit"]')
          .not('[readonly]').filter(':visible');

      if (e.shiftKey) {
          focusable.eq(focusable.index(this) - 1).focus();
      } else {
          var next = focusable.eq(focusable.index(this) + 1);
          if (next.length) {
              next.focus();
          } else {
              focusable.eq(0).focus();
          }
      }

      e.preventDefault();
  }
});

// 新規作成ボタンの処理
//入力が空だった場合
{
  const createBtn = document.getElementById('new-create');
  createBtn.addEventListener('keypress', onkeyPress);
  createBtn.addEventListener('click', onClick);
  
  const email = create_account.email;
  const password = create_account.password;
  
  function onClick() {
    if (email.value == "" && password.value == "") {
      alert('メールアドレスとパスワードを入力してください');
      return false;
    } else if (email.value == "") {
      alert('メールアドレスを入力してください');
      return false;
    } else if (password.value == "") {
      alert('パスワードを入力してください');
      return false;
    }
  }

  function onkeyPress(e) {
    if (e.keyCode == '13') {
      onClick();
    }
  }
}

//各正規表現について
{
  const createBtn = document.getElementById('new-create');

  //メールアドレス
  const form_email = document.getElementById('email');
  const email_regexp = /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/

  // パスワード
  const form_password = document.getElementById('password');
  const password_regexp = /^(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,100}$/

  const form_re_password = document.getElementById('re-password');

  createBtn.addEventListener('click', regExp);
  createBtn.addEventListener('keypress', regExpKey);
  
  function regExp(e){
    if (form_email.value != "" && form_password.value != "") {
      if (form_email.value.match(email_regexp) === null) {
        alert('有効なメールアドレスを入力してください');
        return false;
      } else if (form_password.value.match(password_regexp) === null) {
        alert('有効なパスワードを入力してください');
        return false;
      } else if (form_password.value != form_re_password.value) {
        alert('パスワードの入力値が一致しません');
        return false;
      } else {
        alert('アカウントを作成しました');
        return e.preventDefault();
      }
    }
  };

  function regExpKey(e) {
    if (e.keyCode == '13') {
      regExp();
    }
  }
}
```
</div></details>

##制作過程
###1.HTML&CSS部分
メールアドレスとパスワードを入力してアカウントを登録することを想定したフォームを作成

![スクリーンショット 2020-08-16 21.57.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662094/7969828e-ea33-2caf-5679-3e3022c81121.png)

###2.javascript（ユーザーの操作部分）
####①エンターキーを押して次の入力欄に移動する機能
マウス操作の手間省くことができた。
また、KeyCodeの存在を知ることができた。

コードについては、下記のURLの内容から、必要なコードを抜粋。
[WebフォームでEnterキーを押したときにフォーカスを移動させたい](https://fueiseix.hatenablog.com/entry/2018/03/13/203423)

②クリックイベント
2つのデータを入力し、送信ボタンでデータを送信する機能
前述したとおり、こちらは次回に。

###3.javascript（正規表現）
①入力制限
メールアドレスの場合は、@を使った書式になっているかどうか
パスワードの場合は半角数字・半角英字のみ使える、文字数制限の設定

パスワードと確認用のパスワードに入力された値が同じ場合のみ
アカウント作成が行える。
という構想のもと以下のようにコードを書いた。

```js:encryption.js
  //formの各要素を取得&正規表現
  //メールアドレス
  const form_email = document.getElementById('email');
  const email_regexp = /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/

  // パスワード
  const form_password = document.getElementById('password');
  const password_regexp = /^(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,100}$/

  const form_re_password = document.getElementById('re-password');
```

②アラート
新規作成ボタン押し、データの入力が正常の場合、成功アラート表示

失敗した場合は、エラーメッセージを出し、どこが間違っているかを指摘
1.フォームに空欄になっている箇所があるかどうか
2.メールアドレスは〇〇＠〇〇.〇〇の書式に当てはまっているかどうか
3.パスワードは数字英字どちらも1文字以上使われていている、かつ、合計８文字以上になっているかどうか
4.確認用パスワードは1回目のパスワードと同様になっているかどうか

これらを人まとまりにすると、コードが複雑になったので
空欄の場合と入力されている状態とで、関数を別にした。

いずれも新規登録ボタンを押した際に呼び出している。

```js:encryption.js
  //空欄の場合
  const createBtn = document.getElementById('new-create');
  createBtn.addEventListener('keypress', onkeyPress);
  createBtn.addEventListener('click', onClick);
  
  const email = create_account.email;
  const password = create_account.password;
  
  function onClick() {
    if (email.value == "" && password.value == "") {
      alert('メールアドレスとパスワードを入力してください');
      return false;
    } else if (email.value == "") {
      alert('メールアドレスを入力してください');
      return false;
    } else if (password.value == "") {
      alert('パスワードを入力してください');
      return false;
    }
  }

  function onkeyPress(e) {
    if (e.keyCode == '13') {
      onClick();
    }
  }
```

```js:encryption.js
  createBtn.addEventListener('click', regExp);
  createBtn.addEventListener('keypress', regExpKey);

  //何らかの値が入力されている場合  
  function regExp(e){
    if (form_email.value != "" && form_password.value != "") {
      if (form_email.value.match(email_regexp) === null) {
        alert('有効なメールアドレスを入力してください');
        return false;
      } else if (form_password.value.match(password_regexp) === null) {
        alert('有効なパスワードを入力してください');
        return false;
      } else if (form_password.value != form_re_password.value) {
        alert('パスワードの入力値が一致しません');
        return false;
      } else {
        alert('アカウントを作成しました');
        return e.preventDefault();
      }
    }
  };

  function regExpKey(e) {
    if (e.keyCode == '13') {
      regExp();
    }
  }

```

##参考サイト
[JavaScriptで暗号化と復号化を行う方法を現役エンジニアが解説【初心者向け】](https://techacademy.jp/magazine/21244)

###フォーム関連

[【初心者向け】0からformがわかる｜HTMLでのフォーム作成](https://webliker.info/79009/)

[WebフォームでEnterキーを押したときにフォーカスを移動させたい](https://fueiseix.hatenablog.com/entry/2018/03/13/203423)

[JavaScriptで実現！入力フォームの値を取得してチェックする方法](https://www.sejuku.net/blog/91384)

###正規表現
[MDN:クライアント側のフォームデータ検証](https://developer.mozilla.org/ja/docs/Learn/Forms/Form_validation)

[JavaScriptの正規表現(RegExp)の書き方・使い方について解説](https://www.e-loop.jp/knowledges/18/)

[JavaScriptで空判定する方法](https://dev-lib.com/japascript-is-empty/
)

[JavaScriptで同値チェックを実装してHTML5と同じデザインのエラーを出す方法](https://xn--web-s70e101eh74aq95bj6d.xn--vcki1fxh883oon2c.com/%E8%A8%98%E4%BA%8B/40/)

###データ取得
[テキストボックスに入力された値を取得する - JavaScript プログラミング](https://www.ipentec.com/document/javascript-get-textbox-value)

###その他
[qiita:input type=submit でページを更新"しない"方法。](https://qiita.com/Phiyory18/items/cfa1c1c756c7f54e98ab)

[MDN:Event.preventDefault()](https://developer.mozilla.org/ja/docs/Web/API/Event/preventDefault)

##次回
入力されたデータを取得し、保存しておく機能
(JSONやAjaxについて学習しておく)

(追記:9/4)
PHPを使ってログイン機能を実装する。
暗号化：アカウント作成→データを登録→データを暗号化

復号化は次々回。