Fork me on GitHub
#clojure
<
2020-06-30
>
ouvasam08:06:41

This has been also posted on #ring Hi, I have some troubles to have a secure session cookie with ring I tried all the solutions i could find on the web, but it does not work and i still have a cookie named "ring-session" once i set a value in the session. The cookie name is not reflected and the cookie not secure Here is my code

(defroutes app-routes
           (GET "/" req  {:body  (str req)
                          :session {:test 1}}))

(def my-api-defaults
  (-> secure-api-defaults
      (assoc-in [:session :store] (cookie-store))
      (assoc-in [:session :cookie-name] "JSESSIONID")))

(def app
  (-> (handler/site app-routes)
      (wrap-defaults my-api-defaults)))

(defn start-server
  []
  (run-jetty app {:port 9291
                  :ssl? true}))

(defn -main [& args]
  (start-server))
Does someone have any ideay on what i am doing wrong ? (i use tomcat to deploy the war )

ouvasam08:06:41

This has been also posted on #ring Hi, I have some troubles to have a secure session cookie with ring I tried all the solutions i could find on the web, but it does not work and i still have a cookie named "ring-session" once i set a value in the session. The cookie name is not reflected and the cookie not secure Here is my code

(defroutes app-routes
           (GET "/" req  {:body  (str req)
                          :session {:test 1}}))

(def my-api-defaults
  (-> secure-api-defaults
      (assoc-in [:session :store] (cookie-store))
      (assoc-in [:session :cookie-name] "JSESSIONID")))

(def app
  (-> (handler/site app-routes)
      (wrap-defaults my-api-defaults)))

(defn start-server
  []
  (run-jetty app {:port 9291
                  :ssl? true}))

(defn -main [& args]
  (start-server))
Does someone have any ideay on what i am doing wrong ? (i use tomcat to deploy the war )

jumar10:06:18

You should mention that you posted this in #ring https://clojurians.slack.com/archives/C0A5GSC6T/p1593506540098400 Follow ups should go there

ouvasam10:06:48

@ ok sorry. i did modify the original, hoping this is ok

borkdude10:06:13

Is there a library which has split out the dynaload code for clojure spec and clojurescript spec into a library of its own? I've done it for this PR: https://github.com/metosin/malli/pull/210/files but I think it would be convenient to have this as a re-usable library. If no-one has done that so far, I might do it myself.

dave.lapes11:06:57

Hello 🙂 I am having troubles decoding JSON date into java.time.LocalDateTime. I am using schema.core . I really tried googling how to make the LocalDateTime work, but I just can't find the way. And I don't want to use joda time, which by the way works. Compojure is throwing an exception that the string is not an instance of LocalDateTime. Could you please help me a little?

kwladyka12:06:51

(defn calc-expiry-date [expiry-days]
  (->> (.plusDays (LocalDate/now) expiry-days)
       (.format (DateTimeFormatter/ofPattern "yyyy-MM-dd"))))
You can use Java interop

kwladyka12:06:01

I found it the simplest solution for me

kwladyka12:06:27

the example is not exactly what you need but it shows how it works

kwladyka12:06:27

I don’t use shema so I can’t help more in this context

dave.lapes12:06:41

Yeah, that's not the case though. My issue is: • Request coming to Compojure endpoint • Exception is thrown, because provided value is not an instance of LocalDateTime This looks like that somewhere during middleware stuff it doesn't parse the string to LDT correctly. And I don't know where to add it.

kwladyka14:06:47

Just do it with your code

kwladyka14:06:05

again I don’t use Compojure so I don’t know if there is some trick for this

kwladyka14:06:06

I don’t think ring middleware parse dates in reqquest

kwladyka14:06:19

but I can be wrong

dave.lapes14:06:48

Well, there must be a point where JSON data is being decoded.

dave.lapes14:06:39

And I can't find the place where I would inject the support for LocalDateTime object. Because it only has problem with types like this (they don't support it, I have to do it manually for some reason).

dave.lapes14:06:19

Also, it doesn't matter if it is Ring or Compojure, because Compojure accepts Ring wrappers too. And even custom wrappers. But I don't think providing custom decoder for whole body is performant. It's like a matter of missing protocol, I don't know.

dave.lapes14:06:07

I just found out that all I have to do is use Jsonista inside my Ring middleware.

dave.lapes14:06:14

But I can't figure out how to insert it there, ah.

dave.lapes14:06:16

The docs are so bad...

dave.lapes14:06:47

They are promoting the cooperation between those 2 libraries, but there is nothing about their common configuration.

kwladyka15:06:23

I use this (wrap-json-body {:keywords? true :bigdecimals? true}) for JSON

kwladyka15:06:57

I thin if you will describe your issue with past of exception, show exact moment of this exception, some etc. it will be easier to help

kwladyka15:06:15

On the end I am not sure what is your problem

kwladyka15:06:32

words are too general 😉

dave.lapes16:06:28

I created a Pastebin of the exception

kwladyka16:06:48

I don’t know schema but is just looks like you have to coerce date to java.time.LocalDateTime before validation. I think you have to id yourself by your own code.

kwladyka16:06:08

unless schema has some coerce features, but I don’t know this

kwladyka16:06:55

so you have to parse this string into LocalDateTime

kwladyka16:06:32

I don’t think any middleware or anything will guess this string has to be convert into LocalDateTime

dave.lapes16:06:01

Hmmmm. That sounds reasonable. Thank you a lot. I was getting confused. I already spent a lot of time on that. I am going to try that and keep you posted.

dave.lapes17:06:39

Looks like it wasn't a mistake of schema 🙂

dave.lapes17:06:55

Cause schema can't do anything about it. So, like I said, it was screwed somewhere in the middleware chain.

dave.lapes17:06:04

(defmethod ring-swagger/custom-matcher LocalDateTime [_] #(LocalDateTime/parse %))

dave.lapes17:06:08

This fixed it 🙂

olle14214:06:45

How can I do something like this

; in utils ns
(def my-values [vals...])

; in main ns
(def values-name "my-values")

; in main ns
(utils/values-name)

borkdude14:06:42

@olle142 Look at resolve

olle14214:06:49

Thanks! Can I somehow use resolve and not have to use ns-resolve? I'm using clojurescript and ns-resolve doesn't seem to be available here

borkdude14:06:53

In CLJS this doesn't work. You can maybe use analyzer/resolve-var in a macro

borkdude14:06:58

Ask in #clojurescript

mike145214:06:34

@fabrao Here is an example:

(import 'java.security.SecureRandom)
(def rand-gen (SecureRandom.))

(defn rand-big-number
  "generate random number using given bits length"
  [bit-length]
  (let [buf-length (quot bit-length 8)
        b-array    (byte-array buf-length)]
    (.nextBytes rand-gen b-array)
    (BigInteger. b-array)))

(rand-big-number 160)

fabrao14:06:02

Thank you mike

somedude31418:06:44

I am getting the desired output here, but wondering if there’s a simpler way to arrive to the result?

(def table {:home {:uri 1, :handler 11}, :out {:uri 2, :handler 22}})
(apply merge (map #(into {} {(first %) (:uri (second %))}) table))
=> {:home 1, :out 2}

dpassen118:06:40

(reduce-kv (fn [m k v] (assoc m k (:uri v))) {} table)

dpassen118:06:55

Sean’s version will work just as well. Destructuring the uri key being the only difference

ataggart16:07:23

These are always fun.

(zipmap (keys table)
        (map :uri (vals table)))

seancorfield18:06:43

I would probably use reduce-kv for that...

(reduce-kv (fn [m k {:keys [uri]}] (assoc m k uri)) {} table)
(oops, pressed return too soon)

somedude31418:06:00

Awesome, thanks, apply and merge made me sense I was doing something convoluted :)

dstephens19:06:59

Hi all! I'm trying to write a kubernetes operator in clojure. I've looked at a few alternatives and the easiest looked like with java interop and I'd started following this tutorial https://developers.redhat.com/blog/2019/10/07/write-a-simple-kubernetes-operator-in-java-using-the-fabric8-kubernetes-client/ However that tutorial is based on a library which uses Java class based marshalling/unmarshalling of kubernetes events. Has anyone used clojure to interop with that sort of thing before, presumably it can be done with gen-class and then converting to a clojure map afterwards (by hand, with datafy, clojure/java.data, bean-dip-esque things)? Is there a nicer way than that? Alternatively has anyone had experience using nubank/clj-kubernetes-api, exoscale/clojure-kubernetes-client, or other to set up an operator and would suggest doing it this way instead? They both seem very low level so I'd probably have to write code to watch for changes and things myself unless someone knows that's been done before? Thanks!

noisesmith20:06:07

the implements keyword means that it's only using an interface and doing no concrete inheritance

noisesmith20:06:30

that means you can use defrecord, deftype, or reify instead of gen-class (and all of those are much simpler to use)

noisesmith20:06:47

if you only ever need one instance, and don't need the class to have a statically known name, reify is simplest, then use deftype if you don't need map behavior, or defrecord if you do

dstephens20:06:24

I may have picked a bad example class to link as the others all seem to extend CustomResource or some variant, though I am not certain that they have to so I will test that out, thanks! I think I have to pass the class around for things to reference, and unfortunately I think I'll have to set up the getters and setters for jackson databind, I'll see where that leaves me 🙂

noisesmith20:06:42

also, if you need concrete inheritance but a generated class-name is OK, proxy is easier to use compared to gen-class

dstephens20:06:57

that's a good point, hadn't looked at proxy yet. Also just seen I can annotate fields in deftype (at least) with :volatile-mutable, not sure I like the idea but I might see if jackson will fall back to setting the field directly if a setter doesn't exist

noisesmith20:06:39

you can crate a setter via a protocol (defprotocol ImyFoo (setBar [this value])) (deftype Foo [^:volatile-mutable bar] ImyFoo (setBar [this v] (set! bar v))) something like that

noisesmith20:06:10

NB

Note well that mutable fields are extremely difficult to use
  correctly, and are present only to facilitate the building of higher
  level constructs, such as Clojure's reference types, in Clojure
  itself. They are for experts only - if the semantics and
  implications of :volatile-mutable or :unsynchronized-mutable are not
  immediately apparent to you, you should not be using them.

noisesmith20:06:31

you can put an atom in a field, and swap inside the setter for thread safety

noisesmith20:06:06

you'd wan't a getter that derefs of course, it would be part of the same protocol defining the setter

dstephens20:06:52

Yeah that's reasonable, I'm hopeful that these are very much at the edge and really only jackson will use them and then I'll immediately convert to a map and throw them away so I'm not too worried about the thread safety, and I started in java so know mostly what I'm dealing with, but since performance doesn't matter here anyway the atom idea is a good one

dstephens20:06:31

I'm kind of hoping with the mutable fields I can avoid some of the extra protocols that I really don't want to be defining in the first place, but that's probably too much laziness!

noisesmith20:06:37

it's easy to write correct code that uses an atom and convert to a volatile once you know you need it

noisesmith20:06:41

the reverse is harder

noisesmith20:06:06

well, you can't have getter/setters as a bean expects with fields, mutable or no

noisesmith20:06:31

I mean yeah you could name the field "getFoo" and then you have half as many things to implement, but that seems a little hacky

dstephens20:06:02

Oh I agree, I'm just wondering if the bean is a hard requirement for jackson to work. I remember using JAXB or something an age ago and it would use a setter if it was there, otherwise it would try to access the field directly, otherwise it would use the constructor. There was a whole host of fallbacks before it failed

dstephens20:06:49

But thanks for the help, I think I have a few things to go and tinker with from this and if I mess up mutable state it will only be my own fault now! 😉

noisesmith20:06:35

quick repl experiment

(ins)user=> (defrecord whatever [a b])
user.whatever
(ins)user=> (bean (->whatever 1 2))
{:class user.whatever, :empty false}
(ins)user=> (defrecord whatever [getA getB])
user.whatever
(cmd)user=> (bean (->whatever 1 2))
{:class user.whatever, :empty false}
(ins)user=> (defprotocol Iwhatever (getA [this]) (setA [this val]) (getB [this]) (setB [this val]))
Iwhatever
(ins)user=> (defrecord whatever [^:volatile-mutable a ^:volatile-mutable b] Iwhatever (getA [this] a) (setA [this v] (set! a v)) (getB [this] b) (setB [this v] (set! b v)))
Syntax error macroexpanding defrecord at (REPL:1:1).
:volatile-mutable or :unsynchronized-mutable not supported for record fields
(ins)user=> (deftype whatever [^:volatile-mutable a ^:volatile-mutable b] Iwhatever (getA [this] a) (setA [this v] (set! a v)) (getB [this] b) (setB [this v] (set! b v)))
user.whatever
(cmd)user=> (bean (->whatever 1 2))
{:a 1, :b 2, :class user.whatever}

noisesmith20:06:00

"bean" is just a function that tries to give you a hash map version of a bean

dstephens20:06:44

yeah good point, if I can't leverage some nice conversion out from the type I create it definitely weighs in favour of not being lazy and setting up my protocols!

dstephens20:06:49

this https://github.com/wjoel/clj-bean and https://github.com/clojure/java.data also looked kind of useful from my travels, first one requires aot unfortuantely (I think)

noisesmith20:06:13

if you were feeling cheeky you could make a pojo macro that defines a randomly named interface and a deftype with mutable fields all in one go

noisesmith20:06:41

since the naming is all trivial and machine generatable

noisesmith20:06:12

user=> (gensym "Ipojo")                                                                                                                                                                               
Ipojo1278  
etc.

noisesmith20:06:32

you could even through the class name in there for clarity

dstephens20:06:20

:+1: I had started looking at that actually, I don't have much experience with macros but probably enough to get started, it would be really nice, I have to pass in a 'kind' which defined the kubernetes kind to listen for so I can use that as the class name

noisesmith20:06:16

this is definitely the easiest kind of macro - just expanding from a template in a loop for each field, rather than weird bindings and conditionals

dstephens20:06:56

weird bindings and conditions is the bit I know though 😆

dstephens21:06:20

Well it will definitely need some work to make pretty 😆 but it's functioning! Thanks for the help today 😊

dstephens21:06:49

ahh just realised I need an empty constructor 😢 alas, might have to fall back on gen-class or proxy, one for tomorrow anyway!

sveri20:06:07

Hi. I have a web handler that uses the wrap-defaults function from ring.middleware.defaults. This includes the anti-forgery middleware. When I load my page I have the af-token generated and supply it via a form in my post request. The post request contains the token as expected, but still I get an error that my af-token is invalid. So I debugged the code and it turns out that the session should contain the af token, but the actually my request does not contain anything in the :session map. This is the code I refer to: https://github.com/ring-clojure/ring-anti-forgery/blob/master/src/ring/middleware/anti_forgery/session.clj#L8, it returns null. Any ideas what might be wrong here?

clojurians-slack10021:06:33

This sounds like something we've gone through in an ongoing project.

clojurians-slack10021:06:02

Is your session middleware set up?

sveri21:06:59

I am not sure what you mean exactly by setup. It's part of the site-defaults: https://github.com/ring-clojure/ring-defaults/blob/master/src/ring/middleware/defaults.clj#L101 So it's definitely called, is there something else to setup?

clojurians-slack10021:06:16

I'm trying to rattle my own brain to try and remember what exactly our issue was and how we solved it 😝. IIRC it had something to do with the session.

sveri21:06:03

Yea, it must have, somehow, well, thanks for trying 🙂

clojurians-slack10021:06:23

What does your config to wrap-defaults look like?

clojurians-slack10021:06:37

Looks like we ended up disabling [:security :anti-forgery] in wrap-defaults config and manually calling wrap-anti-forgery when necessary 😟

posobin21:06:32

Is the ring-session cookie set by the server successfully?

posobin21:06:03

Do you send the post request to the server with credentials enabled?

posobin21:06:53

Look in the dev console at the actual headers sent in the post request, ring-session should be there.

posobin21:06:19

Is that a cross-origin post request?

sveri09:07:23

So, I figured what the problem actually is. I have the following code:

(routes
      (wrap-api (partial api-routes db) db dev?)
      (wrap-base home-routes dev?)
      (wrap-base (partial user-routes config db) dev?)))
where each wrap- function wraps the route with middlewares. anti-forgery works for the first home-route, but not for the second user-routes anymore if I do it like this. Changing the code to this:
(wrap-base
      (routes (home-routes) (user-routes config db))
      dev?)
works, but I cannot apply different middlewares to different apis like this. But thats another problem. Maybe that helps solving your problem @

sveri09:07:43

what seems to work is to wrap it all in routes again like this:

(routes
      (wrap-api (api-routes db) db dev?)
      (wrap-base
        (routes (home-routes) (user-routes config db))
        dev?))
where the wrap- functions apply different middlewares.

clojurians-slack10010:07:34

Hmmm 🤔. I'll have a look, thanks.

timur05820:06:07

Is there a library in Clojure that would allow writing the whole dynamic front-end logic on the server, but sync updates/events with client browser via web socket connection? I believe there’s such a framework for Elixir language, and I thought it would be a pretty neat and simple way to write rich web apps without learning JS/React/CLJS.

lilactown20:06:19

there's a lib called ripley which is working on this

smith.adriane21:06:01

are there links for either the elixir library or the clojure ripley library? they sound interesting

timur05821:06:12

How neat is that! Pretty neat I must say

timur05821:06:38

@tatut and the author is here!

lilactown21:06:38

the elixir lib is called phoenix liveview

somedude31422:06:26

https://htmx.org (formerly Intercoolerjs) is also an interesting option in that area and it's language agnostic.

coneillcodes23:06:05

I feel like im just falling back into declarative programming here is there a way to do this without the ifs?. I have a 10x10 vector board. Im placing "M" when there is a slot available. If I picked the same spot I just want to try again.

(defn place-moles
  []
  (loop [n 10]
    (println n)
    (let [x (rand-int 10)
          y (rand-int 10)
          open? (= "*" (get-in @board [x y]))]
      (if (pos? n)
        (if open?
          (do
            (swap! board assoc-in [x,y] "M")
            (recur (dec n)))
          (recur n))))))

l0st3d11:07:02

You could always separate out the generation of the coords from the actual updating of the board. Maybe something like this:

(def board (atom nil))

(defn random-coord []
  (inc (rand-int 9)))

(defn generate-mole-coords [b]
  (->> (repeatedly #(vector (random-coord) (random-coord)))
       distinct
       (remove #(get-in b %))
       (take 10)))

(defn place-moles [b moles]
  (reduce #(assoc-in %1 %2 :mole) b moles))

(defn place-moles-on-board! []
  (swap! board place-moles (generate-mole-coords @board)))

(comment

  (place-moles-on-board!)
  @board
  )

l0st3d11:07:05

That way you can always keep the domain code that generates the new state separate from the stateful code that updates the atom

l0st3d11:07:00

Bear in mind though that if you want the update to the atom to guarantee to add 10 unique moles, you'll need to move more code inside the function that swap! calls, as both these solutions have a read-then-modify bug which will break what I think you want to do if you run it from multiple threads (for example)

me115915:07:40

so the read bug basically everything would have to happen in swap to make sure so thats why you made functions for everything

l0st3d15:07:59

It's only really a problem if you have 2 threads updating the board at once. You could fix it by moving the check to see if each coord is already on the board into the function called by swap!

l0st3d15:07:40

but if you're just using the board as a global variable and not sharing it between threads, then it's not really a problem

me115915:07:04

cool. and whats the relevance of the ! at the end of the place-moles-on-board! function. I notice theres like some unspoken conventions on method naming based on what it does.

me115915:07:47

Its obviously a pretty simple game im making not looking to spread this across hundreds of threads or something ha

l0st3d15:07:58

the ! tends to be used to signify that running this function performs some side effects

l0st3d15:07:01

if you're playing with a game to learn idiomatic clojure, it's often best to try to learn to write small pure functions and reduce the amount of side effecting code as much as you can

me115915:07:36

yea im fairly new to clojure which is why I posted. I felt like I was just falling into writing declaritve stuff and it didn't "look" clojure. Ive been trying to just get a simple event loop just to play with structure https://github.com/ThrowsException/whack-a-mole

l0st3d15:07:07

I think you mean "imperative" when you say "declarative" ... Declarative code tends to be stateless, for example, using a map as a look up table

noisesmith23:06:47

you can unfold nested ifs into cond (cond (and (pos? n) open?) (do ...) (pos? n) (recur n) :else nil)

noisesmith23:06:40

also, you could "lift" the loop arg into a function arg, since functions are recur targets

noisesmith23:06:10

I find a linear set of cond clauses easier to understand than nesting, YMMV

noisesmith23:06:15

use whatever is most readable

coneillcodes23:06:53

yea. ill try the cond. I was just thinking that had to be a way to do like single statement but the addition of needing to check if I need to (dec n) makes it more difficult.

coneillcodes23:06:31

would it be better to just loop finding an open spot rather than the whole thing maybe?

coneillcodes23:06:46

eh actually the conds are nice. thanks @noisesmith