Day11 CSSと微修正（セキュリティ確認）

#グラフ編集ページのCSSと微修正
完成後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565105/423ad026-66b3-d28c-c8e5-d32dfceb7c92.png)
**グラフに登録するアクション**
グラフに登録するアクションは、graphsコントローラのcalculateアクションであるが、実はこればホーム画面にもあって、完了後の行き先はホーム画面に戻るようになっている。
グラフ編集ページも同じアクションを使うとリダイレクト先がホームになってしまうので、同じアクションをもう一つ作ってリダイレクト先を変えた。
ユーザがいたページとかを記憶するか、ユーザがいたページを条件式にしてリダイレクト先を変えるということもできるのだろうか。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565105/79f45ac8-fdab-01c7-13aa-407b37ad406b.png)
調べたらあった・・・。
アクションのリダイレクト前で、ホームをインクルードしていればこっち、そうじゃなければグラフ編集ページにリダイレクトというif文でもできそう。
**paginateが機能する場合としない場合がある問題**
結論から書くと、paginateが参照している変数というのはアクションから作成されたもので、paginateのリンクをクリックすると、そのpaginateが作成されたアクションのあるURLをもう一度実行しているらしい。
１./graph/edit/:idからグラフ編集ページにリンクしたときのpaginateの挙動：もう一度/graph/edit/:idにアクセス。
2./graphfe/:idからグラフ編集ページにリンクしたときのpaginateの挙動:もう一度/graphfe/:idにアクセス。
今回はアクションを二つわけて、そのためにURLも別にしたために、paginateが参照するURLが条件によってわかれてしまい、片方のURLがRouteに記載されていなかったために発生した。なお帰ってくる変数は同じなのでデータが変わるとかはないが、これも上述じたrequest.refererを使っていればここまで修正する必要はなかったと思う。
俯瞰的に考えて、目先のエラーを直すのもいいけど、それによってどういう弊害がでてくるのかということはしっかりと考えてからやりたい。
#Footer
Footerは下記のようにすることで、常にボディ部分は１００％表示で、もしそれ以上の要素が入ってきてもさらにのびるようにしている。またポジションを指定することでFooterは必ずボディ部分の下に張り付く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565105/f933eee3-6202-1078-23b9-dd6e658dbe06.png)
#セキュリティ関係
##ユーザーコントローラ
**new（登録ページ表示）,create　（新規登録）**
1.全てのユーザが何の条件もなしに実行可能。
**show　（プロフィール表示）**
1.ログインしていることが必要・・・Before action (logged_in_user)
2.プライベート設定がオフであることが必要・・・Before_action(private）
→Admin、非公開ユーザ自身はその限りでない。
3.存在するユーザでであることが必要・・・Before_action(exsist)
**Edit（編集ページ表示）,Update（プロフィール更新）**
1.ログインしていることが必要
2.正しいユーザであることが必要（編集しようとしているユーザが自分自身（Current_user)・・・Before_action(correct_user)
>>追記　悪意あるユーザは、UpdateがParamsのIDから更新する対象を特定しているとわかって、URLでアップデートパスを投げるかもしれない。（POSTはcurl?とかいうやつでコマンドラインから実行できるみたい）、だからそのときのために、まずログインしていること、そしてさらにログインしていても正しいユーザであることをBefore_actionで設定している。そうすればidを記入したUpdateをGETでもPOSTでも投げられても、実行はされない仕組み）
さらに、StrongParameterで、送信されてきてDBに渡せるコラムを制限しているのでAdminが乗っ取られることもない。
ただ、Pribate属性に関してはStrongParameterで許可をしている。（プロフィール設定更新の際に、非公開設定も変更できるようにしているため。
Privateコラムを許可しているということはcurl?コマンドで送信されてきても許可されてしまう。ただし、Update先のURLに万一不正なPrivate属性を紛れ込まされていたとしても、その前のBefore_action(Correct_user)で弾かれるので大丈夫なはず。

**Index(ユーザ一覧表示）**
1.ログインしていることが必要
2.Adminであることが必要（Privateユーザ表示）
>>2.に関してはBefore_actionのAdminを使わずに、Viewでif admin?のみで制限している。その理由はIndexコントローラはPrivate以外のユーザも表示するメソッドも含まれていて、もしIndexコントローラにBefore_actionを入れてしまうと、Adminユーザ以外が見れなくなるという状況になるからである。
もちろん、Admin用とそれ以外のユーザ用でIndexアクションを分ければBefore_actionでのフィルターも実装できただろうが、やっている最中は気がつかなかった。
Viewのif currentuser.admin?は突破されないのだろうか。
突破するには多分currentuserにAdmin属性を含ませる必要があり、currentuserのAdmin属性をTrueにすることはUpdateアクションがStrongParameter等で制限していることからできない。
次にAdminのCurrent_userをのっとるとすると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565105/4b252373-a9a4-b52a-fb4d-175f27e42600.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565105/e8478909-4250-67db-bc6e-280707a59946.png)
session[:id]をAdminのそれにすることができれば乗っ取られてしまうかもしれないが、それをするにはパスワードを突破しなくてはならない。セッションIDをメールアドレスから生成するlog_inメソッドはuser.authenticate後に実行されているから。
セキュリティの知識もコードの知識も、curlコマンドがどこまでできるかの知識も全部足りないけど、おそらくif admin?はセキュリティ上問題ないように思える。
よって、Privateユーザ一覧もAdmin以外にみられることはないはず。
ここまで書いたけど、BeforeActionのadminもif文のAdminもやっていることはcurrent_user.admin?で一緒だけど、アクションが実行されるかされないかが大きな違いである。

**Destroy(ユーザ削除）**
1.Adminであることが必要・・・Before_action Admin、アクション内でのif文によるフィルター、ビュー内でのif文によるフィルター（一般ユーザにはボタンが表示されない）
**goalicon(目標達成のアイコン付与**（1/30追加）
1.ログインしていることが必要
2.正しいユーザであることが必要
>２については、自分以外のユーザのIDをURLに含ませて別のユーザのアイコンを作成されることを阻止するために加えた。
２のBefore_actionでは、paramsから検索したユーザと、current_userを比べている。link_toなどでコントローラのアクションに行く時にそこでcurrent_userを入れてしまうとBefore_actionの意味がなくなってしまうので、current_userは使わずparamsを最後まで使うよう注意した。
途中でcurrent_user.idから生成したIDをURLに入れると、必ずBefore_actionを突破できてしまうからということ。


##グラフコントローラ
**Calculate Calculatefe (グラフに日付、体重登録）**
1.ログインしていることが必要・・・Before_Action
2.正しいユーザであることが必要・・・Before_Action
3.正しい日付フォーマットであることが必要・・・Before_Action（dateformcheck)
>>CalculateとCalculatefe（feはfrom editの略。グラフを編集する専用ページからPOSTするとこのアクションになる。）は両方とも、URLにユーザの固有IDのParamsを持つ。またBefore_actionのcorrect_userもユーザのparamsを元に正しいユーザとログイン中のユーザを比較しているので、このcorrect_userもそのまま使える。
3.についてはDay12に詳細を記載したが、受け付ける日付データをXXXX-XX-XXのみにした。そうしないと、日付変換メソッドがその値以外を扱えないのでエラーが出てしまう。

**Edit(グラフ編集ページを表示）**
1.ログインしていることが必要・・・Before_Action
2.正しいアカウントであることが必要・・・Before_Action
>>
EditアクションがGETされるパスはややこしいことに二つあるが（理由は上述したとおり）、それぞれのURLは、
  get '/graphfe/:id', to: 'graphs#edit'・・・Calclateが実行されたあとに読み込まれる
  get '/graph/edit/:id', to: 'graphs#edit'・・・プロフィールページからのリンク先を押下したときに読み込まれる。
で、両方ともに:idはユーザの個別IDをずっと引き継いでくれているので、ここでもcorrect_userを使うことができる。

**Destroy(グラフデータを削除)**
1.ログインしていることが必要・・・Before_Action
2.正しいユーザであることが必要・・・アクションでフィルター
>>
グラフデータの削除は、グラフデータの個別IDを削除のリンク先に含めて、そのparamからデータをコントローラのアクションが特定して、削除しているので、before_actionのcorrect_userの期待しているparamsはユーザIDなので使うことができない。
そのため、グラフデータの削除は、そのデータと紐づいているuser_idがログインしているユーザのそれと一致しているかどうかをアクション内で確認することでフィルターとしている。（グラフテーブルはユーザIDを外部キーにもつため、必ずuser_idがグラフデータには関連しているし、グラフ作成時にcurrent_userからグラフを作成しているcurrent_user.graphs.build~~、自分のIDとグラフデータは関連づいている）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565105/2cc03257-b5a7-f8de-1054-5711a6a46a39.png)

**Destroybmi(BMIと身長データを削除)**
1.ログインしていることが必要・・・Before_Action
2.正しいアカウントであることが必要・・・Before_Action
>>１．２に加えて、アクション内でBMIデータの前提となる身長データもあることというフィルターもかけている。

##いいねコントローラ
**create createfromin**
1.ログインしていることが必要・・・Before_Action
2.存在しているユーザIDであることが必要・・・Before_Action
3.まだいいねのデータがないことが必要・・・Validation
４.プライベート設定がオフであることが必要・・・Before_action(private）

>>いいねデータ（user_idと、pro_id)を作るアクションは二つあって、ユーザプロフィールページからのそれと、ユーザ一覧ページからの二つである。
ログインしていることをフィルターにしないと、cretaeのアクション内ではcurrent_userのメソッドを使っているので万一、いいねを作成するPOSTリクエストをログインせずに送られるとエラーになってしまう。そのためBefore_Actionを加えた。
３に関しては、user_idとpro_idの組み合わせが一意という制約を加えることにより、たくさんのいいねを量産することができないようにした。また、アクションレベルでも、下記のようにすることでこれから作ろうとしているいいねデータが存在している時はリダイレクトさせ、注意を促すようにした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565105/cbeb4a06-bdf4-6496-83a4-5fdcbb623a10.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565105/3376b38a-ad3e-456c-2364-4bdd0b767247.png)
また４については、プライベート設定のユーザIDをURLに入れてPOSTリクエストされた場合、いいねができてしまうため、それを防止するためにフィルターをかけた。destroyも同じく、存在しえないいいねに対して既にBefore_actionのチェックがあるが、ここでも制限を設定した。

**destroy destroyfromin**
1.ログインしていることが必要・・・Before_Action
2.いいねデータの存在チェック・・・Destroyアクション内
3.存在しているユーザIDであることが必要・・・Before_Action
４.プライベート設定がオフであることが必要・・・Before_action(private）

**likelist,likedlist**(1/28追加機能）
1.ログインしていることが必要・・・Before_Action
2.存在しているユーザIDであることが必要・・・Before_Action
3.プライベート設定がオフであることが必要・・・Before_action(private）
>>
2については例えば/likeslist/9999などといった存在しないユーザIDをURLに入れられると、アクションではparamsからUserデータを探すのでそこでエラーが出てしまう。
よって、存在チェックのフィルターをかけることで、それを防止する必要があった。
３については、非公開設定ユーザのいいねリストを他のユーザから見られないようにした。（Adminや非公開設定ユーザ自身を除く）

##コンタクトコントローラ
**form(問合せフォーム表示）,create（問合せ投稿）**
1.ログインしていることが必要・・・Before_Action
**destroy(投稿された問合せ削除/Adminのみ）**
1.Adminであることが必要・・・Before_Action(correct_user_contact_and_extst)
2.存在していることが必要・・・Before_Action(correct_user_contact_and_extst)

>>paramsが削除するデータ固有のIDなのでcorrect_userは使うことができない。そのため別のメソッドを作成し、対応した。メソッドでは、Adminであることのチェックに加え、投稿が存在しているチェックもするようにした。
また、削除ボタンもビューでif current_user.admin?とすることで一般のユーザには見えないようになっている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565105/5b9e6535-1fe0-e7ab-24e7-89095e8d18c4.png)
<img width="619" alt="スクリーンショット 2020-01-22 4.07.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565105/fc536f5e-a284-0084-0c9a-bde8713ad932.png">

##コメントコントローラ
**put(コメントを投稿する。具体的にはコメントした人の名前、ID、された人のID（user_idは外部キー）、内容、あれば画像がSaveされる）**
1.ログインしていることが必要・・・Before_Action
2.プライベート設定がオフであることが必要・・・Before_action(private）
3.存在していることが必要・・・Before_Action(exist)
>>そもそもPrivateユーザのコメント投稿画面のあるプロフィールは表示ができないが、URLを直接POSTで送られた時はここで対策しておく必要がある。そのためBefore_actionでフィルターをかけている。対象のユーザが非公開であり、ログインしているユーザがAdminではなく、また対象のユーザが自分自身ではない時、Before_action(private)は作動する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565105/86f14299-e3d7-d93e-e61d-b4931618d1b5.png)
また存在チェックを加えることで、コメント投稿しようとする寸前にユーザが削除された場合にエラーが出ることを対策している。
なお、存在チェックではrequest.refererを使っていないが、それはその場合、リダイレクト先が存在しないユーザのページになってしまい、そこでまたexistが働き、そしてまたページがリダイレクトされるというループに陥ってしまうためである。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565105/d64e93cf-775b-efac-5eed-981f06d5bc14.png)

**destroy**
1.ログインしていることが必要・・・Before_Action
2.正しいユーザであることが必要・・・Before_Action（correct_user_comment_and_exist）
3.存在していることが必要・・・Before_Action（correct_user_comment_and_exist）
>>正しいユーザというのは今回はAdminと、その投稿をした人、その投稿エリアのプロフィール主の三人である。これらのフィルターは以下のようにした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565105/10e58ae2-29ed-3f10-d952-65bd6e883b0b.png)
まずparamsに入っているIDは削除リンクで生成されてるコメントごとの固有IDなので、そのレコードを取得する。
そしてそのレコードのput_idつまりコメントした人がログインしている人、または、user_idつまりコメントされた人がログインしている人、そしてAdminのいずれかであれば削除アクションが実行できるようになっている。
一応、ビューレベルでも削除ボタンは上の三種類のユーザしか表示されないようにしている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565105/c79b56cd-ad65-bec1-4841-d9fcac8e6170.png)

#思ったこと
ロジックを書く上で、どの値（paramsからとるのか、current_userからとるのか、paramsからとるならそのURLに入っているparamsはユーザIDなのか、それともeach文とかに入れられて出てきたまた別のデータの固有IDなのかといったこと）を基準にして修正や構築をするのかを考えながらやるのは非常に大事だと思った。
また、しっかりとビューとコントローラそしてアクション、さらにはルートをみて、理解することでparamsで混乱することはなくなるし、適切にparamsをうまく使うことができれば実装できる機能の柔軟性は非常に柔軟なものになると思った。

#これから
CSSとセキュリティの確認・修正が終了したので、あとはグラフ表示関係のバグを潰したい。
それが終わり次第Herokuへデプロイを一度し、そこでコードのリファクタリング、テストコードの作成に入る。
とりあえずグラフにどれくらいかかるかがわからないけども、明日はグラフを直したい。