Bulletin board system
https://en.wikipedia.org/wiki/Bulletin_board_system
youtube 資料
古いの
https://youtu.be/Dddbe9OuJLU
わりと最近 ( 温故知新 )
https://youtu.be/wqqhSz2fLVw
いろんな言語で書いてみたいが、web framework を使って プログラムする方法を知るために、まず、Ruby と web framework を sinatra にして、どうやって掲示板をプログラミングするかを並べていく。
sinatra
https://sinatrarb.com/
Ruby と Sinatra での Hello World までは、
できるだけわかりやすい Ruby + Sinatra で web アプリ
Hello World までのことが理解できたら、手順はわかるので、BBS って何だっけ?ということを浅く、ふかーく掘ってみると拡張するアイデアがでる基礎がならされてくる。
まず、なんだっけ?というとこから、これを見てコピペで実行した。
100行未満かつGo標準ライブラリだけで作る掲示板
著者:クジラ飛行机
https://news.mynavi.jp/techplus/article/gogogo-9/
Go 言語でのコンパイルまでの手順を知っていれば、全くくじけず掲示板プログラムのミニマムな仕様が感じられるいい記事だと思った。
その後、二週間か三週間くらい、4chan 8chan の事件、なぜ 2 チャンネルが開始されたのか、関連事件など記事や映像を掘って読み続けた。
The case for anonymity online
https://www.ted.com/talks/christopher_moot_poole_the_case_for_anonymity_online?language=en
Fredrick Brennan @[email protected]
https://twitter.com/fr_brennan/status/1197461945307131905?s=20&t=od7Bucc3KHDWPnixxI1Bcg
https://mobile.twitter.com/fr_brennan/status/1566445269771755523
https://twitter.com/infinitechan/status/848139757758562304?s=20&t=XDUEGtuxavkH4t-m8kYI6ALeaked voting machine BIOS passwords may implicate Q-friendly county clerk | Ars Technica
Who Owns 4chan?
https://www.wired.com/story/who-owns-4chan/
掲示板を、使えるレベルにするには、どうやってコメントを掃除するかという点が重要なことだ、きっと。
古典的な chat のルールや機能をよく確認するべき。minecraft や、minetest の privileges などが参考にがなるかもしれない。
管理者ではなく、ユーザー側でブロックしたい書き込みを非表示にする twitter のようなブロック機能は、オールドスクールな BBS にはなかったが今後あったほうがいい。
華原朋美さん「ヤフコメさん達には傷つけられてきた」法的処置明かす 投稿者はどうやって特定する?
https://archive.ph/z1o2c
https://youtu.be/s0o3rlwsjOk今日この賞が発表されて、明日からYahoo!ニュースのコメント欄は荒れるでしょう。
https://youtu.be/F-TI3UONAHY
hashtag #dropkiwifarms
https://en.m.wikipedia.org/wiki/Kiwi_Farms
速報: CloudflareによるKiwi Farmsのブロック https://web.gnusocial.jp/post/2022/09/20/
reddit:Aaron Swartz
https://www.troddit.com/r/aaronswartz
さらに、日本の掲示板文化(主に perl で作られる BBS 1995 - 2006 )について
『あやしいわーるどの歴史』(2006/09/28 現在)
http://f16.aaacafe.ne.jp/~stwalker/
広告表示なし
とりあえず、ローカルホストで戰います。
アドレス http://127.0.0.1
のポートナンバー 4567
localhost:4567
詳細は、
できるだけわかりやすい Ruby + Sinatra で web アプリ
https://crieit.net/posts/Ruby-Sinatra-web
をクリアするとわかります。
色は違いますが、掲示板の感じはこうなります。
BBS
├── bbs.rb
├── bbsdata.db
├── lockfile
├── views
│ ├── badrequest.erb
│ ├── board.erb
│ ├── ca.erb
│ ├── created.erb
│ ├── layout.erb
│ ├── login.erb
│ ├── loginfail.erb
│ └── logout.erb
│
├── public
│ └── css
│ └── style.css
│
│ #[ bundle init ]
├── Gemfile
│ #[ bundle install ]
├── nender #auto generated
└── Gemfile.lock #auto generated
#frozen_string_literal: true
source "https://rubygems.org"
gem "activerecord"
gem "sqlite3"
gem "sinatra"
gem "webrick"
どれも数行だけのコード。
コードへのリンク
https://rentry.co/ngg3s
コードへのリンク
https://rentry.co/gyd6v
コードへのリンク
https://rentry.co/t92tk
コードへのリンク
https://rentry.co/2fnu9
コードへのリンク
https://rentry.co/og7h7
コードへのリンクコードへのリンク
https://rentry.co/nh37f
コードへのリンク
https://rentry.co/x6ofg
コードへのリンク
https://rentry.co/tab3d
コードへのリンク
https://rentry.co/wbw99
require 'digest/sha2'
require 'active_record'
require 'sinatra'
set :environment, :production
set :sessions,
exprre_after: 70000,
secret: 'assdffgfhjjkklaslllg'
ActiveRecord::Base.establish_connection(:adapter=>'sqlite3',:database=>'bbsdata.db')
class BBSdata < ActiveRecord::Base
self.table_name = 'bbsdata'
end
class Account < ActiveRecord::Base
self.table_name = 'accounts'
end
# keepers able to delete scum comments.
class Keeper < ActiveRecord::Base
self.table_name = 'keepers'
end
class Kickaccount < ActiveRecord::Base
self.table_name = 'kickaccounts'
end
# html sanitizer
helpers do
def h(text)
Rack::Utils.escape_html(text)
end
end
get '/' do
redirect '/login' # create account
end
get '/ca' do # create account
erb :ca
end
get '/ca2' do # create account
@message = "Change username.The username is already in use."
erb :ca
end
post '/create' do
@username = h(params[:username])
@username.gsub!("\"|\\","")
@username.gsub!(/;/,"")
rawpassword = h(params[:passwd])
rawpassword.gsub!("\"|\\","")
rawpassword.gsub!(/;/,"")
begin
f = Account.find(@username)
if f.id == @username
puts "Change username.The username is already in use."
redirect '/ca2'
end
rescue =>e
puts "OK.Username has accepted."
end
lock = File.open("lockfile","r+")
lock.flock(File::LOCK_EX)
algorithm = "100"
rand = Random.new
spice = Digest::SHA256.hexdigest(rand.bytes(20))
hashed = Digest::SHA256.hexdigest(rawpassword + spice)
ca = Account.new # create account
ca.id = @username
ca.salt = spice
ca.hashed = hashed
ca.algorithm = algorithm
ca.save
lock.close
erb :created
end
get '/login' do
erb :login
end
get '/created' do
session[:username] = @username
erb :created
end
get '/board' do
@u_name = session[:username]
if @u_name == nil
redirect '/badrequest'
end
begin
kicked_account = Kickaccount.all
kicked_account.each do |kv|
if kv.userid == @u_name
puts "kick out: #{kv.userid}"
redirect '/logout'
end
end
rescue => e
puts "error"
end
@admin = ""
puts "you are #{@u_name}."
begin
roomkeeper = Keeper.find(@u_name)
@admin = roomkeeper.id
puts "you are roomleeper."
rescue => e
puts "you are not roomkeeper."
end
all_data = BBSdata.all
if all_data.count == 0
@table = "<tr><td>This BBS is Empty.</td></tr>"
else
@table = ""
kicked = []
all_data.reverse_each do |one|
if one.k == 1
kicked << one.userid
kicked.uniq!
end
n1 = one.userid.size
n2 = one.entry.size
str1 = ""
str2 = ""
n1.times do
str1 += "■"
end
n2.times do
str2 += "■"
end
@table = @table + "<tr>"
@table = @table + "<td style=\"witdh: 5%\">#{one.id}</td>"
if one.v == 0
@table = @table + "<td>[#{one.userid}]</td>"
else
@table = @table + "<td>[#{str1}]</td>"
end
@table = @table + "<td><font size=\"-2\">#{Time.at(one.writedata)}</font></td>"
if (one.userid == @u_name && one.v == 0) || (@admin != "" && one.v == 0)
@table = @table + "<td><form action=\"/delete\" method=\"post\">"
@table = @table + "<input type=\"hidden\" name=\"id\" value=\"#{one.id}\">"
@table = @table + "<input type=\"hidden\" name=\"_method\" value=\"delete\">"
@table = @table + "<input type=\"submit\" value=\"Delete\"></form></td>"
else
@table = @table + "<td></td>"
end
@table = @table + "</tr>"
if one.v == 0
@table = @table + "<tr><td style=\"word-break: break-word\" colspan=\"4\">#{one.entry}</td></tr>\n"
else
@table = @table + "<tr><td style=\"word-break: break-word\" colspan=\"4\">#{str2}</td></tr>\n"
end
if @admin != "" && @admin != one.userid && !kicked.include?(one.userid)
@table = @table + "<tr><td><font size=\"-2\">#{one.addr}</font></td>"
@table = @table + "<td><form action=\"/kick\" method=\"post\">"
@table = @table + "<input type=\"hidden\" name=\"bbsdataid\" value=\"#{one.id}\">"
@table = @table + "<input type=\"hidden\" name=\"_method\" value=\"delete\">"
@table = @table + "<input type=\"submit\" value=\"Kick\"></form></td></tr>\n"
elsif @admin != "" && @admin != one.userid && kicked.include?(one.userid)
@table = @table + "<tr><td><font size=\"-2\">#{one.addr}</font></td>"
@table = @table + "<td><form action=\"/kickback\" method=\"post\">"
@table = @table + "<input type=\"hidden\" name=\"bbsdataid\" value=\"#{one.id}\">"
@table = @table + "<input type=\"hidden\" name=\"_method\" value=\"delete\">"
@table = @table + "<input type=\"submit\" value=\"Kickback\"></form></td></tr>\n"
end
@table = @table + "<tr><td colspan=\"4\">_____________________________________________________________________________</td></tr>"
end
end
erb :board
end
post '/new' do
lock = File.open("lockfile","r+")
lock.flock(File::LOCK_EX)
maxid = 0
begin
last = BBSdata.last
if last.id > maxid
maxid = last.id
end
rescue =>e
puts maxid
end
new_comment = BBSdata.new
new_comment.id = maxid + 1
new_comment.userid = h(session[:username])
new_comment.entry = h(params[:entry])
new_comment.writedata = Time.now.to_i
new_comment.v = 0 # invisible : 1
new_comment.addr = @env['REMOTE_ADDR']
new_comment.k = 0 # kicked : 1
new_comment.save
lock.close
redirect '/board' # return to BBS
end
delete '/kick' do
lock = File.open("lockfile","r+")
lock.flock(File::LOCK_EX)
maxid = 0
begin
last = Kickaccount.last
if last.id > maxid
maxid = last.id
end
rescue => e
puts "maxid: #{maxid}"
end
kicked = Kickaccount.new
kicked.id = maxid + 1
username = ""
begin
f1 = BBSdata.find(h(params[:bbsdataid]))
kicked.userid = f1.userid
username = f1.userid
kicked.addr = f1.addr
kicked.save
rescue => e
puts "f1 Error"
end
begin
f2 = BBSdata.where(userid: "#{username}")
f2.each do |matched_one|
puts matched_one.id
matched_one.k = 1
matched_one.save
end
rescue => e
puts "f2 Error"
end
lock.close
redirect '/board'
end
delete '/kickback' do
lock = File.open("lockfile","r+")
lock.flock(File::LOCK_EX)
puts (h(params[:bbsdataid]))
username = ""
begin
f1 = BBSdata.find(h(params[:bbsdataid]))
username = f1.userid
begin
f2 = Kickaccount.all
f2.each do |matched_one|
if matched_one.userid == f1.userid
matched_one.destroy
end
end
rescue => e
puts "f2 Error"
end
rescue => e
puts "f1 Error"
end
begin
f3 = BBSdata.where(userid: "#{username}")
f3.each do |m|
puts m.id
m.k = 0
m.save
end
rescue => e
puts "f3 Error"
end
lock.close
redirect '/board'
end
delete '/delete' do
lock = File.open("lockfile","r+")
lock.flock(File::LOCK_EX)
begin
s = BBSdata.find(h(params[:id]))
# s.destroy
s.v = 1 # invisible
s.save
rescue => e
puts "Delete Error"
end
lock.close
redirect '/board'
end
get '/logout' do
session.clear
erb :logout
end
get '/loginfail' do
session.clear
erb :loginfail
end
#################################
get '/*' do
redirect '/'
end
#################################
#--------------------------------
post '/auth' do
user = h(params[:uname])
user.gsub!("\"","")
user.gsub!(/;/,"")
pass = h(params[:pass])
pass.gsub!("\"","")
pass.gsub!(/;/,"")
redirect_flag = checkFlag(user, pass)
if redirect_flag == "true"
session[:username] = user
redirect '/board'
end
redirect '/loginfail'
end
def checkFlag(check_username,check_password)
redirect_flag = "fail" # go to "/loginfail"
begin
cf = Account.find(check_username)
db_username = cf.id
db_spice = cf.salt
db_hashed = cf.hashed
check_hashed = Digest::SHA256.hexdigest(check_password + db_spice)
if check_hashed == db_hashed
redirect_flag = "true"
puts "go to \"/board\""
end
rescue => e
redirect_flag = "error"
puts "go to \"/loginfail\""
end
return(redirect_flag)
end
create table bbsdata (
id integer primary key,
userid varchar(20),
entry varchar(150),
writedata integer,
v integer,
addr varchar(20),
k integer
);
create table accounts (
id char(20) primary key,
salt varchar(40),
hashed varchar(70),
algorithm char(5)
);
create table keepers (
id char(20) primary key,
salt varchar(40),
hashed varchar(70),
algorithm char(5)
);
create table kickaccounts (
id integer primary key,
userid char(20),
addr varchar(20)
);
データベースのテーブル雛型をつくる。
~/BBS$ sqliter3 bbsdata.db < initdb
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント