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 )

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

@U06BE1L6T 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.

👍 6
David Lapeš11: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

David Lapeš12: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

David Lapeš14:06:48

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

David Lapeš14: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).

David Lapeš14: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.

David Lapeš14:06:07

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

David Lapeš14:06:14

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

David Lapeš14:06:16

The docs are so bad...

David Lapeš14: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 😉

David Lapeš16: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

David Lapeš16: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.

David Lapeš17:06:39

Looks like it wasn't a mistake of schema 🙂

David Lapeš17:06:55

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

David Lapeš17:06:04

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

👍 3
David Lapeš17:06:08

This fixed it 🙂

Risetto14: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

Risetto14: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

mike_ananev14: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)

3
fabrao14:06:02

Thank you mike

adam18: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}

Derek18:06:40

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

Derek18: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)))

👍 3
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)

adam18:06:00

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

Daniel Stephens19: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

Daniel Stephens20: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

Daniel Stephens20: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

Daniel Stephens20: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

Daniel Stephens20: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

👍 3
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

Daniel Stephens20: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

Daniel Stephens20: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

Daniel Stephens20: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!

Daniel Stephens20: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

Daniel Stephens20:06:20

👍 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

Daniel Stephens20:06:56

weird bindings and conditions is the bit I know though 😆

Daniel Stephens21:06:20

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

Daniel Stephens21: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?

walterl21:06:33

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

walterl21: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?

walterl21: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 🙂

walterl21:06:23

What does your config to wrap-defaults look like?

walterl21:06:37

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

Gleb Posobin21:06:32

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

Gleb Posobin21:06:03

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

Gleb Posobin21:06:53

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

Gleb 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 @UJY23QLS1

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.

walterl10:07:34

Hmmm :thinking_face:. I'll have a look, thanks.

Timur Latypoff20: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

phronmophobic21:06:01

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

Timur Latypoff21:06:12

How neat is that! Pretty neat I must say

Timur Latypoff21:06:38

@tatut and the author is here!

lilactown21:06:38

the elixir lib is called phoenix liveview

👍 6
thanks2 6
adam22:06:26

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

👍 3
Chester ONeill23: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))))))

Ed11: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
  )

👍 3
Ed11: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

Ed11: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)

Chester ONeill15: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

Ed15: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!

Ed15: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

👍 3
Chester ONeill15: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.

Chester ONeill15:07:47

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

Ed15:07:58

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

👍 3
Ed15: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

Chester ONeill15: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

Ed15: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

Chester ONeill23: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.

Chester ONeill23:06:31

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

Chester ONeill23:06:46

eh actually the conds are nice. thanks @noisesmith