use cgi dir for better security
[iankelling.org] / _site / comment.rb
diff --git a/_site/comment.rb b/_site/comment.rb
deleted file mode 100755 (executable)
index 14f1152..0000000
+++ /dev/null
@@ -1,332 +0,0 @@
-#!/usr/bin/env ruby
-# encoding: utf-8
-# Copyright (C) 2016 Ian Kelling
-
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 2 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-# debian sets LANG=C when starting apache2.
-# the envoding comment above fixes the internal encoding afaik,
-# Found this at
-# https://stackoverflow.com/questions/20521371/set-utf-8-as-default-for-ruby-1-9-3
-# also note  man ruby's -E arg.
-Encoding.default_external = Encoding::UTF_8
-
-require 'cgi'
-require 'fileutils'
-require 'time'
-require 'sqlite3'
-
-require_relative '../b'
-include B
-
-# constanty things
-DEBUG = true
-CAPTCHA = -> {
-  c = []
-  x = (<<EOF).split("\n")
-What does a dog wag?
-tail
-Would you sleep better on a bed or a keyboard?
-bed
-Are there more or less than one million people on the Earth?
-more
-Which of Lilly and Robert is more commonly a woman’s name?
-lilly
-Which word has fewer letters, adorable or fox?
-fox
-What is the normal color of milk?
-white
-Which of Iceland and Turkey is an island nation?
-iceland
-Is a filesystem like a tree or a rose?
-tree
-What character is a tilde?
-~
-Which is brighter, the moon or the sun?
-(the )?sun
-Which is closer, the moon or the sun?
-(the )?moon
-What language is this sentence written in?
-english
-What animal says "meow" and catches mice?
-cat
-What animal quacks and has webbed feet?
-duck
-Which are better fliers: worms or birds?
-birds
-Which typically runs first: a kernel or a web browser?
-kernel
-EOF
-  while x.length > 0
-    c << x.pop(2)
-  end
-  c
-}[]
-
-def do_captcha
-  captcha_q = CAPTCHA.sample[0]
-  puts "Content-type: text/html\n\n"
-  puts skel('comment.rb', "#{DN}/captcha", <<EOF, ' / <a href="/blog.html">blog</a> / comment-captcha')
-<p>Hello friend. I haven't read a post from #{IP}, and I only remember for a few months, so:</p>
-<p>#{captcha_q}</p>
-
-<form action="/comment.rb" method="post">
-  <input class="misc" type="text" name="url">
-  <input name="goto" type="hidden" value="#{GOTO}">
-  <input name="question" type="hidden" value="#{captcha_q}">
-  <input name="answer">
-<br>Your comment:
-  <textarea rows="10" name="comment" maxlength="1000">#{COMMENT_TXT}</textarea>
-  <input type="submit" value="Submit">
-</form>
-EOF
-  exit 0
-end
-
-
-def fail(msg)
-  if DEBUG and msg
-    puts "Content-type: text/plain\n\n"
-    puts msg
-  else
-    redir
-  end
-  exit 0
-end
-
-def redir
-  File.write('/tmp/x', GOTO)
-  puts 'Status: 302 Found'
-  puts "Location: #{GOTO}#comment-section\n\n"
-  exit(0)
-end
-
-
-def bn(*args)
-  File.basename *args
-end
-
-
-###### begin error checking & arg parsing ######
-cgi = CGI.new
-IP = cgi.remote_addr
-
-if cgi.has_key?('goto')
-  GOTO = cgi['goto']
-else
-  GOTO = '/'
-  fail['redir to /']
-end
-
-if (cgi.has_key?('url') && cgi['url'] != "") || ! cgi.has_key?('comment')
-  fail["comment not in form or url in form. cgi.params: #{cgi.params}"]
-end
-
-COMMENT_TXT = cgi["comment"]
-
-
-if COMMENT_TXT.length > 1000 or GOTO.length > 150
-  fail['length of comment or goto is too great']
-end
-
-
-captchad = false
-if cgi.has_key?('answer') && cgi.has_key?('question')
-  if cgi['answer'].downcase !~ /^#{CAPTCHA.to_h[cgi['question']]}$/
-    do_captcha
-  end
-  captchad = true
-end
-
-
--> {
-  found = false
-  Dir.foreach('blog') do |entry|
-    next if ['.','..'].any? { |f| f == entry }
-    if GOTO == 'blog/' + entry
-      found = true
-      break
-    end
-  end
-  fail['goto entry not found'] unless found
-}[]
-######### end error checking & arg parsing ########
-
-
-$db = db_init
-state = nil
-WHITELIST_CUTOFF = NOW - 4*DAY
-
-
-####### begin: state for ips we've seen before #######
-[[5, 60], # 1 min
- [10, 60*5], # 5 min
- [20, 60*60], # 60 min
- [30, 60*60*24], # 1 day
- [60, 60*60*24*7]] # 1 week
-  .each do |max_posts, date|
-
-  if $db.execute(<<-SQL, [NOW - date])[0][0] > max_posts
-  select count(*) from c
-  where date > ? and ip = '#{IP}'
-SQL
-    state = 'rate_limited'
-  end
-end
-
-state ||= 'suspect' if $db.execute(<<-SQL)[0][0] > 0
-  select count(*) from c
-  where ip = '#{IP}' and (
-state = 'banned' or
-state = 'rate_limited')
-SQL
-
-unless state
-  older_date = NOW - DAY*2
-  last_moderated = $db.execute(<<-SQL, [older_date])[-1][0]
-  select date from c
-  where ip = '#{IP}' and (
-    state = 'moderated' or
-    (date < ? and (state = 'timed' or state = 'known')))
-SQL
-  last_good = $db.execute(<<-SQL, [older_date])[-1][0]
-  select date from c
-  where ip = '#{IP}' and (
-    state = 'picked' or
-    (date < ? and (state = 'timed' or state = 'known')))
-SQL
-  if last_moderated && last_good
-    if last_good > last_moderated
-      state = 'known'
-    else
-      # these 2 waiting conditions are not actually needed,
-      # since waiting is the default, but meh.
-      state = 'waiting'
-    end
-  elsif last_moderated
-    state = 'waiting'
-  elsif last_good
-    state = 'known'
-  end
-end
-####### end: state for ips we've seen before #######
-
-####### begin: whitelist checking #########
-glob = "../blog/#{'?'*'YYYY-MM-DD-'.length}#{bn GOTO, '.*'}.md"
-md_file = Dir[glob][0]
-unless state
-  b = bn(md_file,'.*')
-  post_date = Time.parse(b[0..DATE_LEN]).to_i
-  if post_date > WHITELIST_CUTOFF
-    state = 'timed'
-  end
-end
-###### end: whitelist checking ########
-
-state ||= 'waiting'
-
-if state != 'known' && ! captchad
-  do_captcha
-end
-
-
-# states:
-# timed
-# # was posted a whitelist period, so automatically posted.
-# # whitelist periods are per page times when legit comments are
-# # much more likely than spam, so we automatically let comments through.
-
-# known
-# # ip posted good comment before: either, one in picked state, or
-# # a timed/known comment which is over 2 days old (I saw it and didn't remove
-# # it)
-
-# picked
-# # manually marked as a good comment, so publish it.
-
-# rate_limited
-# # posting too much, consider them a spammer.
-
-# moderated
-# # bad comment, but don't ban them
-
-# banned
-# # all comments from this ip dead, new comment's dont even go into the db.
-
-# waiting
-# # waiting for manual moderation, get's posted automatically if there
-# # is none in 24 hours
-
-# suspect
-# # had a bad post in the past. does not
-# # automatically get posted in time without moderation.
-
-
-# any of the manual states
-date = $db.execute(<<-SQL)[0][0]
-select max(date) from c where
-state = 'moderated' or
-state = 'banned' or
-state = 'picked'
-SQL
-
-# not the bad automatic states
-query = <<-SQL
-select count(*) from c where
-state != 'rate_limited' and
-state != 'suspect'
-SQL
-
-
-if date
-  new_count = $db.execute(query + 'and date > ?',date)
-else
-  new_count = $db.execute(query)
-end
-
-if new_count == 1
-  require 'net/smtp'
-  def send_email(opts={})
-    opts[:to]          ||= ENV['USER']
-    opts[:server]      ||= 'localhost'
-    opts[:from]        ||= ENV['USER']
-    opts[:from_alias]  ||= ENV['USER']
-    opts[:subject]     ||= "test subject"
-    opts[:body]        ||= ""
-
-    msg = <<END_OF_MESSAGE
-From: #{opts[:from_alias]} <#{opts[:from]}>
-To: <#{opts[:to]}>
-Subject: #{opts[:subject]}
-
-#{opts[:body]}
-END_OF_MESSAGE
-
-    Net::SMTP.start(opts[:server]) do |smtp|
-      smtp.send_message msg, opts[:from], opts[:to]
-    end
-  end
-  send_email :subject => 'new comments on iankelling.org'
-end
-
-$db.execute('insert into c values (NULL, ?, ?, ?, ?, ?)',
-            [state,
-             IP,
-             NOW,
-             GOTO,
-             COMMENT_TXT])
-
-post(md_file)
-
-redir