I'm struggling to wrap my head around https://github.com/ring-clojure/ring-anti-forgery in practice if using multiple services. If serving the HTML out of a Clojure webserver it's pretty simple, but if I want to have a separate web server possibly not in Clojure with a Clojure API server, I don't know how best to use the least amount of custom code and most standard techniques to implement CSRF protection with Ring. I've spent a bunch of time reading https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#javascript-automatically-including-csrf-tokens-as-an-ajax-request-header documentation and am pretty confused. It seems like some implementations expose an API on a server that just set a cookie or returns a body with a CSRF token and then expect the same token in a custom header, which sounds simple but doesn't seem to work for me in practice. Anyone have tips for this?
Note that CSRF is specifically a browser attack, exploiting the way the server manages cookies and the various ways in which a user can get tricked into triggering browser requests. If your Clojure server is an API server, i.e. it gets called by non-browser services, CSRF doe snot really apply.
Say if your setup is something like
browser <-> python web server <-> Clojure API
and there is no way for the browser to reach the Clojure API, CSRF is very important in the browser <-> python web server communication, but does not make as much sense in the python web server <-> Clojure API context.Thanks @gaverhae! There was also some discussion I found online indicating CSRF was more important for HTML forms submission and may not apply as much for REST APIs, but I didn't completely understand the nuances. It sounds like if I just route everything through a web server API proxy I don't have to set up CSRF On the API server, but then I just maybe have to worry about it on the web server still
Ring anti forgery depends on ring session, and ring session defaults to a stateful in memory store which can be tricky to make work correctly in certain setups
How are you routing?
For now I am only running the entire project on my local machine. I've got a couple docker containers running on different ports and an API proxy on the web server that just sends certain endpoints to the API server
What library are you using for defining routes
Reitit has some well known gotchas with ring sessions in memory store
If you are using reitit or something else post compojure https://github.com/metosin/reitit/issues/205#issue-399958744 may be a useful read
Oh I was using compojure, sorry I misinterpreted the question. But I'll check that out anyway
The issue described does seem related though, since the session id cookie seems to keep getting updated on every API call from what I was seeing in the browser network tab
CSRF is basically a way to "trick" a web browser into sending a user's credentials along with a command the user did not intend. So it is very specific to the browser context. It is, however, super important in the browser context, so you should absolutely implement it there. And, in an ideal world, you would still have some level of authentication between your internal API server and your web-exposed server.
Hello All I am trying to create a time loop which shows time at regular intervals of time. The many examples that are available online show the use of timeout function. when I execute the following code I expect to see the print of timestamps.
(go-loop [cnt 0]
(when-let [t (<! (timeout 100))]
(if (= cnt 5)
(print (str (time/now)))
(recur (inc cnt)))))
Instead I get
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x5fb2504e "clojure.core.async.impl.channels.ManyToManyChannel@5fb2504e"]
Any ideas?To clarify what Dan was trying to say (the end of his message is a bit garbled), since timeout closes its channel after the elapsed time, the <! operation will return nil, meaning the value t gets bound to is nil, which in turn leads to when-let saying "well, the bound value is nil, so I don't need to do anything", and the whole body of when-let gets skipped. So no print operation ever happens, and you also never recur. What you're seeing is the return value of go-loop, which in this case is a closed channel that "contains" nothing.
Changing when-let to just let will at least get your loop running the expected number of iterations.
go-loop returns a channel which is the result you see there. i suspect your repl is not capturing the output from the thread that is printing and itβs going somewhere else
if you reproduce this in a clj repl i expect you will see your output
ok I'll try
thanks!
user=> (doc timeout)
-------------------------
clojure.core.async/timeout
([msecs])
Returns a channel that will close after msecstimeout doesnβt return a value
yes... I understand that timeout just holds the thread up for the time duration specified..
(go-loop [cnt 0]
(if-let [t (<! (timeout 100))]
(if (= cnt 5)
(do (println (str (java.time.LocalDateTime/now)))
:done)
(recur (inc cnt)))
(println "did not get anything from timeout")))
when-let on itβs return value will never be satisfied then
`yes. so if youyou could also use java.util.Timer or java.util.concurrent.ScheduledThreadPoolExecutor in the JDK
(def exec (java.util.concurrent.Executors/newScheduledThreadPool 1))(.scheduleAtFixedRate exec #(println (java.util.Date.) " hi") 0 5 java.util.concurrent.TimeUnit/SECONDS)something like that is what your friendly Java resource would probably recommend
many thanks @alexmiller
I'm writing an Uno card game while attempting to use REPL-aided development. I want to be able to make one move at a time as I experiment, so it feels like I need an atom and swap function to track the state. Is there a better way to do this?
(comment
(do
(def game-atom (atom (make-init-game)))
(swap! game-atom play-card {:color :red, :type 5})
(swap! game-atom play-card {:color :red, :type 0})
(swap! game-atom play-card {:color :wild, :type :wild})
(swap! game-atom assoc :current-color :blue)
(swap! game-atom play-card {:color :blue :type 8})
(swap! game-atom play-card {:color :blue :type 7})
(swap! game-atom draw-card)
(swap! game-atom update-in [:players 2 :hand]
conj
{:color :blue :type :draw-two})
(swap! game-atom play-card {:color :blue :type :draw-two})
(swap! game-atom update-in [:players 0 :hand]
conj
{:color :blue :type :reverse})
(swap! game-atom play-card {:color :blue :type :reverse})))that was my mistake, I was thinking of drop-last
or just take to decide how many to process really
That is a fine way to do it.
Another way which might illuminate other possibilities would be to represent state as a map passed from function to function. So instead of the game-atom (state) taking play-card and parameters, play-card would get the state as any old map parameter.
Test data in the REPL could then be a declarative sequence of moves resulting in a seq of states (or states-and-moves), letting you inspect from a slightly higher vantage point.
If you haven't already, I can highly recommend watching the https://www.parens-of-the-dead.com. You can find much inspiration there for developing and structuring a game in clojure.
@gar thanks, I'll check that out!
@daveliepmann Thanks for the response! I'm not sure I understand the point about the state map; play-card already takes the contents of the game-atom, which is a map representing game state.
Do you mean something like this code, like my example, but without swapping atom state? Then just observing the state at the end of the threaded calls?
(-> (make-init-game)
(play-card {:color :red, :type 5})
(play-card {:color :red, :type 0})
(play-card {:color :wild, :type :wild})
(assoc :current-color :blue)
(play-card {:color :blue :type 8})
(play-card {:color :blue :type 7})
(draw-card)
(update-in [:players 2 :hand]
conj
{:color :blue :type :draw-two})
(play-card {:color :blue :type :draw-two})
(update-in [:players 0 :hand]
conj
{:color :blue :type :reverse})
(play-card {:color :blue :type :reverse}))
the version without the swaps makes more sense to me. you might find it useful to add a vector that acts as a log of plays, draws and game states (could be useful for debugging)
also instead of threading many calls to play-card etc., you could have a vector of moves, and a reduce that consumes individual data structures describing moves and returns new game state
that way, replacing reduce with reductions would give you a sequence of intermediate states
I am imagining something like
(def moves
[{:action :play-card :data {:color :red, :type 5}}
{:action :play-card :data {:color :red, :type 0}}
{:action :change-color :data {:color :blue}}
{:action :draw-card :data {:player 2 {:color :blue :type :draw-two}}])
also as I look closer at the individual steps, I see a mix of declarative game actions, and place specific data updates - IMHO it's worth the extra work to make every step declarative and move the place specific things into the implementation
eg. when you decide to give players names instead of vector indexes, it's easier if the code to change is in one place
or, when you decide to use a deck instead of hard coding which cards are drawn
this is a great chance to explore event sourcing, and representing games as graphs, if those are at all interesting to you (both of these abstractions are useful beyond games)
@noisesmith
> the version without the swaps makes more sense to me. you might find it useful to add a vector that acts as a log of plays, draws and game states (could be useful for debugging)
The one without the swaps certainly looks cleaner, the problem is that I can't run a single piece of the pipeline at once, hence the need tor the atom. I actually already have a log vector, but it's a simple string--it might be better to log other game states too!
> that way, replacing reduce with reductions would give you a sequence of intermediate states
I like the idea of reducing a collection of moves to see intermediate states, that's really cool.
> this is a great chance to explore event sourcing, and representing games as graphs, if those are at all interesting to you (both of these abstractions are useful beyond games)
I really like graphs, it would be fun to use them! I'll keep event sourcing in mind, too!
with the version using a vector of inputs, you can use butlast to see the state up to a certain step
@noisesmith I used reductions below, it works quite well.
(reductions (fn [game move]
(apply (:func move)
(cons game (:args move))))
(make-init-game)
[{:func play-card :args [{:color :red, :type 5}]}
{:func play-card :args [{:color :red, :type 5}]}
{:func play-card :args [{:color :red, :type 0}]}
{:func play-card :args [{:color :wild, :type :wild}]}])
Can you provide an example of how I might use butlast? butlast can only remove one element, but drop-last can remove multiple, so it seems like I'd want to use drop-lastWhere can I find some good codebases that I can read and learn from? Would you suggest any specific project?
I don't recommend to look too much at other's code. You should become your own teacher. Always ask yourself if there could be a better way of doing something. I recommend reading a lot in the Clojure documentation. Again and again. The Clojure standard library is so full of features and secrets. You will hardly find them all in existing code. Over the time you will discover this. The learning experience is much nicer than just reading other code. In my experience, Clojure is a very learning friendly language. In C++ you need thick books, because you really don't see how to efficiently use all the constructs the language has. In C++ there is a big gap between understanding a language construct and successfully applying it in practice. In Clojure I don't feel such a gap. In Clojure I can read something in the documentation and immediately see how this can be used in the real world. In my experience, learning Clojure is learning to read documentation, while learning other languages is more like hacking around examples that you find in text books or other projects. For me it is a very satisfying experience to read something (for example https://clojuredocs.org/clojure.core/for) and being able to directly start using all of this without the need to learn anything else. The documentation is so full of examples. Quite often there is even exactly what you need. That is so great and so satisfactory! Sorry, I am a bit emotional here. With Clojure I feel like back in the 90s, where computers were new. There was so much to try out and learning was just a personal liaison between you, the documentation and your problem.
I learned a ton from https://github.com/nextjournal/calendula. It's very direct: does something real (book calendar appointments) without excessive indirection.
Depending on where you are on your learning journey, maybe Metabase? There aren't many applications that are open source to read -- and a lot of libraries do "unusual" stuff that isn't always very idiomatic. I generally recommend learning from books (esp. the various Pragmatic Press/Bookshelf Clojure books -- Getting Clojure to start with, Programming Clojure next, Clojure Applied after that), and asking lots of questions here.
speaking of which, Pragmatic is having a flash sale NOW (code = flashsale) for 45% off everything!
Thanks for letting me know @alexmiller (these discounts help brazilian developers a lot).
Thanks for you answer @hbrng.computer. My intent of taking a look at other codebases is based on a vision that "to know how to write good code, we need to be exposed to good code". I believe this approach also helps to see different ways to reach the same goal when writing code to solve a specific problem. Maybe my approach is a bit odd, but I'm taking your suggestion as a valid approach (I never spent too much time on the docs, maybe this is the time to take a further look).