Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: Caffeine – Minimum viable back end for prototyping (github.com/rehacktive)
206 points by aw4y on Nov 16, 2021 | hide | past | favorite | 76 comments



At a minimum, this should be password protected by default.

One of the security lessons from the late 1990s and early 2000s is that things like this quickly get hacked. Many developers forget that a service where all security is handled client-side are easy targets for hacking.

Furthermore: In a lot of cases, people will ship prototypes and run their stuff on top of them long after they have outgrown a critical component.

I have tried to write a universal backend... It's possible, but you really have to work in a permissions model from the beginning. What you'll find is that basic read/write/own enables very basic functionality. Unfortunately, to do anything complicated, you will need to write server-side queries that verify that the user is allowed to do what they are trying to do.


Pretty sure this is meant for prototyping and maybe demoing in controlled environments.

As soon as you involve auth, things get boring and annoying.


Honestly, anything simple. It could be as brain-dead simple as passing a password on the command-line, and then requiring the password as a header.


As much as I hate saying it even a simple token in a url parameter might be ok for a prototype.


> As soon as you involve auth, things get boring and annoying.

No, JWT is easy enough to implement.


JWT is crazy annoying compared to "pass an API key" in the header.


> JWT is crazy annoying compared to "pass an API key" in the header.

An API key and a JSON WEB TOKEN have a completely different purpose. API keys don't solve authorization.

A single JWT provider can authorize many different servers.

Furthermore Go already have several good JWT libraries.


And JWT's don't solve authentication which was the actual problem people were looking to solve. For a prototyping server authn==authz is more than fine.


> And JWT's don't solve authentication which was the actual problem people were looking to solve. For a prototyping server authn==authz is more than fine.

Re-read the OP

> Unfortunately, to do anything complicated, you will need to write server-side queries that verify that the user is allowed to do what they are trying to do.

this is authorization, not authentication. Your assertion is false at first place.

Your comment makes no sense by the way. You'd have the exact same issue with another authorization scheme, the credentials need to come from somewhere.

There no such thing as "prototyping servers" in the wild. Only blatantly unsecure open source servers.


For demo application, there maybe only one user


A very basic REST service for JSON data - enough for prototyping and MVPs!

Features:

    no need to set up a database, all data is managed automagically*
    REST paradigm CRUD for multiple entities/namespaces
    schema validation
    search using jq like syntax 
    CORS enabled
    easy to deploy as container


Just a heads-up, you might want to take down the example website. Now that it's been posted to HN you might see malicious actors.

I also think it's prone to SQL injection at the moment? At least, it's raising a syntax error when inputting an apostrophe.


Yes, don't do this:

https://github.com/rehacktive/caffeine/blob/master/database/...

"INSERT INTO %v (id, data) VALUES('%v','%v') ON CONFLICT (id) DO UPDATE SET data = '%v'"

Use prepared statements and parameters passed to the db driver, not building strings with strings or you are vulnerable to sqli.

I'd also avoid using %v anyway when building strings - safer to use a specific type like %d for int.


Are you saying that %v should be avoided in general, or just in the context of queries? (Go noob who doesn't understand %v)


First, don't build strings like this for sql.

But for other strings built with sprintf, yes I am saying don't use %v unless for debugging, it's just one more avenue where you might be surprised by input, even if you're not building strings for sql. For example, someone might do this with user supplied data:

myoutput := fmt.Sprintf("user:%v",userID)

and if userID is a string like "foo" it'll end up in their string and they won't get what they expect. So better to just put another guardrail on there and insist that the param is an integer or whatever you expect by using %d which will only accept an int - this means you have to convert it to an integer first.

Many vulnerabilities are caused by data not being in the format people expect (not just sqli).


Thanks for the explanation! That is a good point about being data-aware.


In queries, you should use the database/sql.DB interface if possible with your database https://pkg.go.dev/database/sql#DB.Exec

It should sanitize / quote arguments for you and protect against SQL injection. Note that this doesn't mean all data sanitization is performed, just the basic '; do my stuff here; -- type of things.


the reason I went "quick'n dirty" is for the prototyping nature of the project. But I'll fix this anyway, thanks!


Using the db Exec / Query / Query row is the same amount of code and effort the fmt.Sprintf statements. Even in quick-and-dirty mock-ups, it's a good idea to not cut corners there.


There's nothing as permanent as a temporary solution. There's been countless SQL injection vulnerabilities exploited over the past decades with the "I'll fix it later" mindset.

Start with prepared statements by default, they are not more work than formatting strings.


You're right of course, but I think the idea of this software is that the user (and, by extension, their input) are trusted.


Good to start with the right habits. People will put this on the internet, the author did for example.


> You're right of course, but I think the idea of this software is that the user (and, by extension, their input) are trusted.

No, you should enforce the most basic security practices even if the users are "trusted". Somebody might put that on the internet for a demo for client and get hacked in no time, because the code is opened to SQL injection. This isn't acceptable. There are minimum security standards every project should follow.

And since none of the minimum security standards are implemented in that project, I would not recommend using it until they are.


I'm not sure what you are "no"-ing. I agreed with the parent comment.


>>Now that it's been posted to HN you might see malicious actors.

This needs to be an HN fN Masterclass by @Dang....

We should have regular visibility into /how/ HN is used by malicious actors.... HN has enough pedigree to get some insight from some of the top security folks... and it would be REALLY good to know how HN is being harvested in this space.


Feature request: supply .json file via command line to pre-load data into the in-memory database.

Taking it even further; how about persisting the data in the file?

Sometimes your prototype will need some pre-added data so I think this might be useful.


I have used WireMock in the past that supports pre-defined mocks. It can be run both locally and as a service (I only ran it locally)

http://wiremock.org/

It's more complex than Caffeine, but it has a lot of options.

It can also run as a proxy and generate the mocks from actual http requests passing through the proxy


currently there are two implementation for the database "behind": in memory or with postgres, both with zero config (except for starting an instance of postgres, in the second case!). it can be easily extended to use files as persistence, good idea :)

regarding the pre-population, you can just make a quick script with curl that will add some data after you run the service. any thought?


Thats code folks would have to write instead of focusing on the MVP, it would be better if this loaded it by convention.


SQLite could also be a good option


My first thought too, but I guess it's also very easy to hand-roll an init_data.sh script with a bunch of POST curls to populate the DB.


exactly!


Can probably do that with some `jq` and CURL magic already!


FYI, there is a name clash with Caffeine, a Mac OS menu bar app that keeps the screen awake: https://intelliscapesolutions.com/apps/caffeine . But I guess this is expected with a name like this, and the scopes of the projects are clearly different, so this should be relatively harmless.


And also a (very efficient) Java cache library https://github.com/ben-manes/caffeine


You don't need an app. `caffeinate` is a command line utility built into macOS.


Caffeine is also a central nervous system stimulant of the methylxanthine class.


And a gnome shell extension that does the same thing.


Since we are collecting :) there is also a streaming service https://www.caffeine.tv/


A few requests should randomly fail to force the developer to think about handling errors. :)


Hah! I'm not sure my MVP has ever had error handling beyond "Something went wrong.". That's something for a real production app, not the minimum possible product.


You guys have errors in your programs? :)

Jokes aside… chaos engineering is a big deal right now - this isn’t a terrible idea and might be worthy of a fork.


Another similar project that I use for mocking API server https://github.com/typicode/json-server


I realize this is just for prototyping but it looks like it just spits sprintf SQL strings into the database.

While not a security risk if done locally, why not just use a where string builder to generate the $ values and a variadic as the input? It's about the same amount of work.


I could have used something similar recently, but that persisted to disk as json. I ended up just storing a wad of JSON on disk and memory, loading and saving as needed. Will only ever be 1M or so and only 2 users.


Shameless plug: along the same lines, but for rapid web UI prototyping cases where you don't want to waste time with setting up a server, I built a tiny tool called REM[0] a few years ago.

It never actually stores data on the server (it echos it into a cookie instead), so the dataset is only ever visible to you, no auth or service keys required.

[0] http://rem-rest-api.herokuapp.com/


Nice to see that the interface for the DB was separated out:

https://github.com/rehacktive/caffeine/blob/master/service/s...

It's not "MVP" fashion but even for only one implementation making these interfaces is critical IMO.

That said, if it's not too much maybe consider adding a SQLite backend! :)


the SQLite implementation is in TODO :)


Similar project -> https://sheet2api.com/


Only 25 rows are supported in the free plan and the other plans are more expensive.

I don't think this has a good price-performance ratio - all other solutions I know are cheaper...


We tried to do this back in 2016 with BrightWork. We got a lot of traction, but it came on the heels of Parse being shutdown by Facebook after acquiring them for a ton of money.

The lesson I learned from that experience is that there is still a tremendous amount of distrust in platforms that make it easy to stand up something quickly. Even prototyping.

Even if you make it easy for users to export their code from your platform you will still run into scalability questions (i.e. what happens if someone builds the next Flappy Bird on your platform?).

All that aside, this is great! Congrats on launching Caffeine. :)


`"CREATE TABLE IF NOT EXISTS %v ( id text PRIMARY KEY, data json NOT NULL)"`

Correct me if I'm wrong, as I havent used Postgres in a few years, but doesn't the `json` column in Postgres just store the data as text?

Last I knew, jsonb was much more efficient/performant for queries and storage, while having a very robust api for querying specific properties.

Curious what the reasoning was for using json rather than jsonb.


Correct. The json data type is less performant and stores the data more or less as lightly indexed text. jsonb optimizes the storage format and allows for more JSON operations, such as extracting individual keys.

For this product, if the super-generic API doesn't offer/require a need to do complex operations, though, json may be adequate to lookup items by id and present them.


Like the idea. Any user auth?

I wonder if parse is still around and supported? I thought that was pretty good for this kinda thing.


Parse is still around and supported: https://github.com/parse-community/parse-server


This is bizarre. I spent a good 5+ min looking over the README and documentation site, and couldn’t find out what that project is other than “a backend that runs on Nodejs.” Yeah ok but what is it? Why am I interested? I’m not looking to be sold, just for it to tell me what it’s for. I have some assumptions based on how I got linked there, but this is surprising to me.


In a nutshell a place for your web page or mobile app to store and retrieve data. There is some auth, business logic / security stuff but not as much as you get in an MVC web app. Let’s you build apps where a lot of the work happens on the front end and the back end is basically a place to save to disk.

Parse was a startup but they shut down and open sourced their code.


I think auth is the trickiest thing to solve in a BaaS solution. Could not find anything in the readme about it.


If you mean https://parseplatform.org/ then it looks to be still around.


Cool project! Personally I've been using apiary or Snowboard for Backend prototyping since they allow for a design first approach and typically end up with quite good Dokumentation and Testing infrastructure. But having a real interactive back end like caffeine provides is also very intriguing!


This awesome! Our product supports json as a backend in a very simple way in order to feed data to HTML templates (https://www.stack55.com) and I was thinking of doing something very similar to what you have done.


very cool :)


Very cool. You could simplify the tests by using testify [0] assertions and possibly a test suite. Then it'd be easier to add additional test cases.

[0] https://github.com/stretchr/testify


Why do people overload common nouns so much when naming a project? A name should confer its essence.


You know, naming is one of the two really hard problems in CS. But there is apparently a hack which is to open dictionary on random page and point your finger on random word.

My next application is going to be called Toreutics which is going to break this word for every person that actually uses it.

Kinda like breaking the word Meta. Which I suppose is actually aimed at making things difficult to search for.


Caffeine suggests a jump start, which is what this tool purports to do.


This is useful. But you can achieve the same results in just a few more steps with Hasura or Supabase and end up with something that is close to production ready.


Yeah, I would probably go hasura if I needed this, but I can see the appeal of something that is a single component you can self host and self understand. Hasura is rock solid, but I will never read through it‘s haskell source or understand how it constructs those extra-clever postgres queries.

If I read it right, you don‘t need to configure any schema to use this? You can just POST a user and it will create that type? If it‘s true, that‘s a real step above hasura/supabase for rapid prototyping.


yes, no schema required (but you can add it if you want validation)


Very nice idea! I haven't seen anything like it.


Looks great indeed


Cool! I like that it's zero config to start with, and that adding schemas can itself just be done with a request.


This may become very useful! I will definitely check it out.


Sorry if this is a little off topic, but what is it with devs and naming projects Caffeine?

Am I the only person who rolls their eyes when I see another Caffeine / Coffee named project?


I wish devs would stop naming EVERYTHING after common english words; it makes stuff 10 times harder to troubleshoot unless you already rank high on the search results.

I guess HN would be the best place to bring this up in a psa topic but I doubt it'll have any long-term influence...


Imagine if Gosling had gone with Oak, there are so many more trees to work with.

Of course Indonesian islands were the other possibility...




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: