diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..163eb75 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*.cr] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0bb75ea --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/docs/ +/lib/ +/bin/ +/.shards/ +*.dwarf diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..151a16e --- /dev/null +++ b/LICENSE @@ -0,0 +1,65 @@ +Microsoft Public License (Ms-PL) + +This license governs use of the accompanying software. If you use the +software, you accept this license. If you do not accept the license, +do not use the software. + +1. Definitions + + The terms "reproduce," "reproduction," "derivative works," and + "distribution" have the same meaning here as under U.S. copyright + law. + + A "contribution" is the original software, or any additions or + changes to the software. + + A "contributor" is any person that distributes its contribution + under this license. + + "Licensed patents" are a contributor's patent claims that read + directly on its contribution. + +2. Grant of Rights + + (A) Copyright Grant- Subject to the terms of this license, + including the license conditions and limitations in section 3, + each contributor grants you a non-exclusive, worldwide, + royalty-free copyright license to reproduce its contribution, + prepare derivative works of its contribution, and distribute its + contribution or any derivative works that you create. + + (B) Patent Grant- Subject to the terms of this license, including + the license conditions and limitations in section 3, each + contributor grants you a non-exclusive, worldwide, royalty-free + license under its licensed patents to make, have made, use, sell, + offer for sale, import, and/or otherwise dispose of its + contribution in the software or derivative works of the + contribution in the software. + +3. Conditions and Limitations + + (A) No Trademark License- This license does not grant you rights + to use any contributors' name, logo, or trademarks. + + (B) If you bring a patent claim against any contributor over + patents that you claim are infringed by the software, your patent + license from such contributor to the software ends automatically. + + (C) If you distribute any portion of the software, you must retain + all copyright, patent, trademark, and attribution notices that are + present in the software. + + (D) If you distribute any portion of the software in source code + form, you may do so only under this license by including a + complete copy of this license with your distribution. If you + distribute any portion of the software in compiled or object code + form, you may only do so under a license that complies with this + license. + + (E) The software is licensed "as-is." You bear the risk of using + it. The contributors give no express warranties, guarantees, or + conditions. You may have additional consumer rights under your + local laws which this license cannot change. To the extent + permitted under your local laws, the contributors exclude the + implied warranties of merchantability, fitness for a particular + purpose and non-infringement. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c25fb9a --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# rethink: it's all in your head. +rethink is an experiment on making content for yourself and nobody else. + +rethink is meant for the rawest form of expression. + +rethink does not include any discoverability, markdown, or thought creation frontend. + +your thoughts do not need to be comprehensible to anyone other than yourself. \ No newline at end of file diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..992ea22 --- /dev/null +++ b/public/index.html @@ -0,0 +1,32 @@ + + + + rethink: it's all in your head. + + +
+

rethink.

+

it's all in your head.

+
+ \ No newline at end of file diff --git a/shard.lock b/shard.lock new file mode 100644 index 0000000..8782f73 --- /dev/null +++ b/shard.lock @@ -0,0 +1,30 @@ +version: 2.0 +shards: + backtracer: + git: https://github.com/sija/backtracer.cr.git + version: 1.2.2 + + crystal-argon2: + git: https://github.com/sushichain/crystal-argon2.git + version: 0.1.3 + + db: + git: https://github.com/crystal-lang/crystal-db.git + version: 0.11.0 + + exception_page: + git: https://github.com/crystal-loot/exception_page.git + version: 0.3.0 + + kemal: + git: https://github.com/kemalcr/kemal.git + version: 1.3.0 + + radix: + git: https://github.com/luislavena/radix.git + version: 0.4.1 + + sqlite3: + git: https://github.com/crystal-lang/crystal-sqlite3.git + version: 0.19.0 + diff --git a/shard.yml b/shard.yml new file mode 100644 index 0000000..95f7466 --- /dev/null +++ b/shard.yml @@ -0,0 +1,26 @@ +name: rethink +version: 0.1.0 + +authors: + - toonlink + +dependencies: + kemal: + github: kemalcr/kemal + + db: + github: crystal-lang/crystal-db + + sqlite3: + github: crystal-lang/crystal-sqlite3 + + crystal-argon2: + github: sushichain/crystal-argon2 + +targets: + rethink: + main: src/rethink.cr + +crystal: 1.7.2 + +license: Ms-PL \ No newline at end of file diff --git a/src/migrate.cr b/src/migrate.cr new file mode 100644 index 0000000..f47ebb6 --- /dev/null +++ b/src/migrate.cr @@ -0,0 +1,17 @@ +require "db" +require "sqlite3" + +db = DB.open "sqlite3:./rethink.sqlite" + +db.exec("CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT, + thought_key TEXT + )") + +db.exec("CREATE TABLE IF NOT EXISTS thoughts ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + author_id INTEGER, + content TEXT, + date DATE DEFAULT (datetime('now', 'localtime')) + )") \ No newline at end of file diff --git a/src/rethink.cr b/src/rethink.cr new file mode 100644 index 0000000..6ff976b --- /dev/null +++ b/src/rethink.cr @@ -0,0 +1,105 @@ +require "kemal" +require "db" +require "sqlite3" +require "crystal-argon2" +require "ecr" + +db = DB.open "sqlite3:./rethink.sqlite" + +class Thought + property :content, :date + + def initialize(content : String, date : Time) + @content = content + @date = date + end +end + +class Thoughts + def initialize(@thoughts : Array(Thought)) end + + ECR.def_to_s "src/views/thoughts.ecr" +end + +get "/~:name" do |ctx| + name = ctx.params.url["name"] + thoughts = [] of Thought + + id : Int32? = nil + db.query("SELECT id FROM users WHERE name = ?", name) do |rows| + rows.each do + id = rows.read(Int32) + end + end + + if id.nil? + ctx.response.status_code = 404 + next "User not found" + end + + db.query("SELECT content, date FROM thoughts WHERE author_id = ?", id) do |rows| + rows.each do + content = rows.read(String) + date = rows.read(Time) + thoughts << Thought.new(content, date) + end + end + + Thoughts.new(thoughts).to_s +end + +get "/" do + render "public/index.html" +end + +# Reuse this later for population scripts +# get "/api/hash" do |ctx| +# Argon2::Password.create(ctx.request.body.as(IO).gets_to_end) +# end + +# post to rethink +put "/api/think" do |ctx| + unless ctx.request.headers.has_key?("authorization") || ctx.request.headers.has_key?("name") + ctx.response.status_code = 401 + next "Unauthorized" + end + + auth = ctx.request.headers["authorization"] + username = ctx.request.headers["name"] + + id : Int32? = nil + thought_key = "" + + db.query("SELECT id, thought_key FROM users WHERE name = ?", username) do |rows| + rows.each do + id = rows.read(Int32) + thought_key = rows.read(String) + end + end + + authorized : Argon2::Response? = nil + begin + authorized = Argon2::Password.verify_password(auth, thought_key) + rescue ex + end + + unless authorized == Argon2::Response::ARGON2_OK + ctx.response.status_code = 401 + next "Unauthorized" + end + + thought = if ctx.request.body.nil? + "" + else + ctx.request.body.as(IO).gets_to_end + end + db.exec("INSERT INTO thoughts (author_id, content) VALUES (?, ?)", id, thought) + ctx.response.status_code = 201 +end + +begin + Kemal.config.env = "production" + Kemal.run +ensure + db.close +end \ No newline at end of file diff --git a/src/views/thoughts.ecr b/src/views/thoughts.ecr new file mode 100644 index 0000000..9a0e92b --- /dev/null +++ b/src/views/thoughts.ecr @@ -0,0 +1,41 @@ + + + + rethink: it's all in your head. + + +
+

rethink.

+

it's all in your head.

+
+<%- @thoughts.reverse.each do |thought| -%> +
+

<%= thought.content %>

+

<%= thought.date.to_s("%a %h %H:%M:%S %Y") %>

+
+<%- end -%> + \ No newline at end of file