Compare commits

...

396 Commits

Author SHA1 Message Date
hrj a53903a757 update scala version in scripts 2024-12-29 18:59:53 +05:30
hrj 12ddf59bd1
Merge pull request #260 from scala-steward/update/scala3-library-3.6.2
Update scala3-library to 3.6.2
2024-12-18 13:31:22 +05:30
hrj 5a5c9a73d9 setup sbt explicitly 2024-12-17 21:14:34 +05:30
Scala Steward a8f50f6098
Update scala3-library to 3.6.2
Signed-off-by: Scala Steward <scala_steward@virtuslab.com>
2024-12-11 17:38:27 +00:00
hrj ab1387814c
Merge pull request #259 from scala-steward/update/scrimage-core-4.3.0
Update scrimage-core, scrimage-filters to 4.3.0
2024-12-04 08:47:38 +05:30
Scala Steward f0d2ddda44
Update scrimage-core, scrimage-filters to 4.3.0
Signed-off-by: Scala Steward <scala_steward@virtuslab.com>
2024-12-03 20:03:13 +00:00
hrj 2fefc62ba2
Merge pull request #258 from scala-steward/update/sbt-1.10.6
Update sbt, scripted-plugin to 1.10.6
2024-12-02 09:56:05 +05:30
Scala Steward 2ec93c4b95
Update sbt, scripted-plugin to 1.10.6
Signed-off-by: Scala Steward <scala_steward@virtuslab.com>
2024-12-01 20:13:15 +00:00
hrj f60cb8dd05 Merge remote-tracking branch 'origin/master' 2024-11-06 06:54:59 +05:30
hrj 5c73a0fea0 scala steward config to signoff commits 2024-11-06 06:54:17 +05:30
hrj 45299fb8eb
Merge pull request #257 from scala-steward/update/sbt-1.10.5
Update sbt, scripted-plugin to 1.10.5
2024-11-06 06:50:50 +05:30
Scala Steward 3c6bbe8c9f
Update sbt, scripted-plugin to 1.10.5 2024-11-05 19:38:15 +00:00
hrj e122976878
Merge pull request #256 from scala-steward/update/sbt-1.10.4
Update sbt, scripted-plugin to 1.10.4
2024-10-31 11:32:55 +05:30
Scala Steward f702a22dcd
Update sbt, scripted-plugin to 1.10.4 2024-10-28 17:16:37 +00:00
hrj b9bd305599 update scala version in test script 2024-10-25 10:45:44 +05:30
hrj f4737424f7 update scala version in scripts 2024-10-25 10:03:18 +05:30
hrj 355e8c553a
Merge pull request #255 from scala-steward/update/scala3-library-3.5.2
Update scala3-library to 3.5.2
2024-10-25 09:52:14 +05:30
Scala Steward 777be7cf08
Update scala3-library to 3.5.2 2024-10-24 18:24:36 +00:00
hrj c7c89a6396
Merge pull request #252 from scala-steward/update/sbt-scalafix-0.13.0
Update sbt-scalafix to 0.13.0
2024-10-24 16:46:43 +05:30
hrj 471a5828cd
Merge pull request #254 from scala-steward/update/sbt-1.10.3
Update sbt, scripted-plugin to 1.10.3
2024-10-22 09:13:04 +05:30
Scala Steward c7327f07ee
Update sbt, scripted-plugin to 1.10.3 2024-10-20 17:55:01 +00:00
hrj aa31b2d9cf
Merge pull request #253 from scala-steward/update/sbt-assembly-2.3.0
Update sbt-assembly to 2.3.0
2024-10-20 22:36:51 +05:30
Scala Steward 592a85257e
Update sbt-assembly to 2.3.0 2024-10-08 17:02:29 +00:00
Scala Steward 5c3160157a
Update sbt-scalafix to 0.13.0 2024-09-28 19:03:49 +00:00
hrj 24ac9c5ee7
Merge pull request #249 from scala-steward/update/sbt-1.10.2
Update sbt to 1.10.2
2024-09-20 22:55:14 +05:30
Scala Steward 6cf0b322fc
Update sbt to 1.10.2 2024-09-16 16:11:09 +00:00
hrj 967145b73b update scala in scripts 2024-08-24 11:17:08 +05:30
hrj 332aac57f0
Merge pull request #248 from scala-steward/update/scala3-library-3.5.0
Update scala3-library to 3.5.0
2024-08-24 11:12:34 +05:30
Scala Steward f6e0130a53
Update scala3-library to 3.5.0 2024-08-23 15:33:05 +00:00
hrj 20f32bdabb update scripts for scala 3.4.3 2024-08-16 10:55:07 +05:30
hrj 660d18d6f2
Merge pull request #247 from scala-steward/update/scala3-library-3.4.3
Update scala3-library to 3.4.3
2024-08-16 10:53:11 +05:30
Scala Steward b786330bff
Update scala3-library to 3.4.3 2024-08-15 16:10:43 +00:00
hrj dbb675b975
Merge pull request #244 from scala-steward/update/scalafmt-core-3.8.3
Update scalafmt-core to 3.8.3
2024-08-15 15:00:11 +05:30
hrj 220eec02b0
Merge pull request #245 from scala-steward/update/scrimage-core-4.2.0
Update scrimage-core, scrimage-filters to 4.2.0
2024-08-13 11:47:38 +05:30
Scala Steward 3e822ef02a
Update scrimage-core, scrimage-filters to 4.2.0 2024-08-12 23:02:17 +00:00
Scala Steward 1c273c1996
Update scalafmt-core to 3.8.3 2024-07-29 18:24:04 +00:00
hrj 7887622040
Merge pull request #243 from scala-steward/update/sbt-1.10.1
Update sbt to 1.10.1
2024-07-11 08:38:27 +05:30
Scala Steward bf303108aa
Update sbt to 1.10.1 2024-07-10 16:58:41 +00:00
hrj cc7e1232f2
Merge pull request #242 from scala-steward/update/scalafmt-core-3.8.2
Update scalafmt-core to 3.8.2
2024-06-14 23:13:16 +05:30
Scala Steward a9b148c1a9
Update scalafmt-core to 3.8.2 2024-06-14 16:56:30 +00:00
hrj 13459fbf21 update scala version in scripts 2024-06-01 16:07:15 +05:30
hrj fa366be315
Merge pull request #241 from scala-steward/update/scala3-library-3.4.2
Update scala3-library to 3.4.2
2024-06-01 15:47:13 +05:30
Scala Steward 9e39f6d293
Update scala3-library to 3.4.2 2024-05-17 16:20:08 +00:00
hrj f0050494a1
Merge pull request #239 from scala-steward/update/sbt-scalafix-0.12.1
Update sbt-scalafix to 0.12.1
2024-05-08 12:24:38 +05:30
hrj 52156b1677
Merge pull request #240 from scala-steward/update/sbt-1.10.0
Update sbt to 1.10.0
2024-05-08 11:33:41 +05:30
Scala Steward 4749486112
Update sbt to 1.10.0 2024-05-07 21:49:03 +00:00
Scala Steward 7c7d7f6633
Update sbt-scalafix to 0.12.1 2024-05-05 16:32:23 +00:00
hrj 17db5767f4
Merge pull request #238 from scala-steward/update/scrimage-core-4.1.3
Update scrimage-core, scrimage-filters to 4.1.3
2024-04-27 21:57:21 +05:30
Scala Steward 3d7b7e8bd9
Update scrimage-core, scrimage-filters to 4.1.3 2024-04-27 16:16:50 +00:00
hrj 1991375d6b
Merge pull request #236 from scala-steward/update/scalafmt-core-3.8.1
Update scalafmt-core to 3.8.1
2024-04-26 08:45:39 +05:30
hrj b77bd94ae6
Merge pull request #237 from scala-steward/update/scrimage-core-4.1.2
Update scrimage-core, scrimage-filters to 4.1.2
2024-04-26 08:45:17 +05:30
Scala Steward b14415add5
Update scrimage-core, scrimage-filters to 4.1.2 2024-04-25 16:16:42 +00:00
hrj ac44980f50 update scripts to scala 3.4.1 2024-04-17 22:59:58 +05:30
hrj fba5b10e77
Merge pull request #235 from scala-steward/update/scala3-library-3.4.1
Update scala3-library to 3.4.1
2024-04-17 22:57:30 +05:30
Scala Steward c4515d3f77
Update scalafmt-core to 3.8.1 2024-03-30 19:11:05 +00:00
Scala Steward 7c394b4359
Update scala3-library to 3.4.1 2024-03-28 17:44:28 +00:00
hrj 6db9934bec
Merge pull request #234 from scala-steward/update/sbt-assembly-2.2.0
Update sbt-assembly to 2.2.0
2024-03-15 09:03:31 +05:30
Scala Steward 39b776fde8
Update sbt-assembly to 2.2.0 2024-03-14 17:32:47 +00:00
hrj 4c3a7ad0fa update dejava font package name 2024-03-04 09:32:39 +05:30
hrj 7f70d60dbb try 17 jre jammy docker image 2024-03-04 09:27:07 +05:30
hrj 4d79567227 use eclipse-temurin containers from adoptium 2024-03-04 09:12:57 +05:30
hrj f6b7278ed1 update scripts to scala 3.3.3 2024-03-04 08:32:35 +05:30
hrj 984bbacb69
Merge pull request #233 from scala-steward/update/scala3-library-3.3.3
Update scala3-library to 3.3.3
2024-03-04 08:27:44 +05:30
hrj 0dd00f5d3e
Merge pull request #232 from scala-steward/update/sbt-scalafix-0.12.0
Update sbt-scalafix to 0.12.0
2024-03-04 08:27:14 +05:30
Scala Steward d355333bd4
Update scala3-library to 3.3.3 2024-03-02 18:55:20 +00:00
Scala Steward 55064c8532
Update sbt-scalafix to 0.12.0 2024-03-02 18:55:14 +00:00
hrj 1742772de1 update jdk version in dockerfile 2024-02-24 09:13:16 +05:30
hrj 1234bd4acb
Merge pull request #230 from scala-steward/update/scalafmt-core-3.8.0
Update scalafmt-core to 3.8.0
2024-02-24 08:49:23 +05:30
hrj df82593d90
Merge pull request #231 from scala-steward/update/sbt-1.9.9
Update sbt to 1.9.9
2024-02-24 08:49:05 +05:30
Scala Steward b782ded765
Update sbt to 1.9.9 2024-02-23 19:34:34 +00:00
Scala Steward aa6a6a1015
Update scalafmt-core to 3.8.0 2024-02-19 23:16:43 +00:00
hrj 157054d9d8
Merge pull request #229 from scala-steward/update/sbt-1.9.8
Update sbt to 1.9.8
2024-01-14 17:03:50 +05:30
Scala Steward daa8903933
Update sbt to 1.9.8 2024-01-12 23:23:08 +00:00
hrj de3a2bad6f
Merge pull request #228 from scala-steward/update/sbt-1.9.7
Update sbt to 1.9.7
2023-12-04 08:03:30 +05:30
hrj 121b190c32
Merge pull request #227 from scala-steward/update/json4s-jackson-4.0.7
Update json4s-jackson to 4.0.7
2023-12-04 08:02:53 +05:30
Scala Steward b95350b1e2
Update sbt to 1.9.7 2023-12-03 16:35:11 +00:00
Scala Steward 26bc159342
Update json4s-jackson to 4.0.7 2023-12-03 16:35:07 +00:00
hrj 476ef499e3
Merge pull request #226 from scala-steward/update/sbt-scalafmt-2.5.2
Update sbt-scalafmt to 2.5.2
2023-12-02 08:26:37 +05:30
hrj 3b925adfde
Merge branch 'master' into update/sbt-scalafmt-2.5.2 2023-12-02 08:15:55 +05:30
hrj 16a8282206
Merge pull request #225 from scala-steward/update/sbt-1.8.3
Update sbt to 1.8.3
2023-12-02 08:14:13 +05:30
hrj 4cedff874d
Merge pull request #224 from scala-steward/update/sbt-assembly-2.1.5
Update sbt-assembly to 2.1.5
2023-12-02 08:13:38 +05:30
hrj d8360c6192
Merge pull request #223 from scala-steward/update/sbt-scalafix-0.11.1
Update sbt-scalafix to 0.11.1
2023-12-02 08:12:46 +05:30
Scala Steward e81e8a77e8
Update sbt-scalafmt to 2.5.2 2023-12-01 17:39:20 +00:00
Scala Steward c045682708
Update sbt to 1.8.3 2023-12-01 17:39:15 +00:00
Scala Steward 414c07beaf
Update sbt-assembly to 2.1.5 2023-12-01 17:39:02 +00:00
Scala Steward aa6607237a
Update sbt-scalafix to 0.11.1 2023-12-01 17:38:57 +00:00
hrj 931ab0a086
Merge pull request #222 from scala-steward/update/scalafmt-core-3.7.17
Update scalafmt-core to 3.7.17
2023-11-19 08:07:43 +05:30
Scala Steward bc4acb1bae
Update scalafmt-core to 3.7.17 2023-11-17 20:29:03 +00:00
hrj 2dc2066ad8
Merge pull request #220 from scala-steward/update/scalafmt-core-3.7.15
Update scalafmt-core to 3.7.15
2023-10-25 07:50:44 +05:30
Scala Steward bc8c6ad227
Update scalafmt-core to 3.7.15 2023-10-24 21:15:37 +00:00
hrj be0612b94d
Merge pull request #219 from scala-steward/update/scrimage-core-4.1.1
Update scrimage-core, scrimage-filters to 4.1.1
2023-10-17 06:59:21 +05:30
Scala Steward fe2315fc89
Update scrimage-core, scrimage-filters to 4.1.1 2023-10-16 22:35:56 +00:00
hrj 1696050702
Merge pull request #218 from scala-steward/update/scrimage-core-4.1.0
Update scrimage-core, scrimage-filters to 4.1.0
2023-09-21 13:47:45 +05:30
Scala Steward 5ddfab95d1
Update scrimage-core, scrimage-filters to 4.1.0 2023-09-20 16:34:22 +00:00
hrj 15c95747e8
Merge pull request #217 from scala-steward/update/scrimage-core-4.0.42
Update scrimage-core, scrimage-filters to 4.0.42
2023-09-20 08:16:41 +05:30
Scala Steward 12bb1dd1e7
Update scrimage-core, scrimage-filters to 4.0.42 2023-09-18 18:01:05 +00:00
hrj 1de046362d update scala version in scripts 2023-09-09 08:31:18 +05:30
hrj f9a089bed1
Merge pull request #216 from scala-steward/update/scalafmt-core-3.7.14
Update scalafmt-core to 3.7.14
2023-09-09 08:27:40 +05:30
hrj caac0552c3
Merge pull request #215 from scala-steward/update/scala3-library-3.3.1
Update scala3-library to 3.3.1
2023-09-09 08:27:02 +05:30
Scala Steward 1701a497b6
Update scalafmt-core to 3.7.14 2023-09-08 22:21:34 +00:00
Scala Steward ecabb6baae
Update scala3-library to 3.3.1 2023-09-08 22:21:25 +00:00
hrj 065748e339
Merge pull request #213 from scala-steward/update/scalafmt-core-3.7.12
Update scalafmt-core to 3.7.12
2023-08-07 09:19:35 +05:30
Scala Steward 707d02a71f
Update scalafmt-core to 3.7.12 2023-08-05 16:15:44 +00:00
hrj a69bd1afaf
Merge pull request #212 from scala-steward/update/scalafmt-core-3.7.11
Update scalafmt-core to 3.7.11
2023-07-31 23:23:56 +05:30
Scala Steward f0f62eb4fc
Update scalafmt-core to 3.7.11 2023-07-30 16:52:14 +00:00
hrj fbaa0f24a8
Merge pull request #211 from scala-steward/update/scalafmt-core-3.7.10
Update scalafmt-core to 3.7.10
2023-07-17 21:47:17 +05:30
hrj ddd4054db1
Merge pull request #210 from scala-steward/update/scrimage-core-4.0.38
Update scrimage-core, scrimage-filters to 4.0.38
2023-07-17 21:46:57 +05:30
Scala Steward 66c93c5069
Update scalafmt-core to 3.7.10 2023-07-16 16:43:51 +00:00
Scala Steward 75ac7b2f88
Update scrimage-core, scrimage-filters to 4.0.38 2023-07-16 16:43:44 +00:00
hrj 367eef011f
Merge pull request #209 from scala-steward/update/scalafmt-core-3.7.8
Update scalafmt-core to 3.7.8
2023-07-13 20:06:36 +05:30
Scala Steward 8be4ad2be8
Update scalafmt-core to 3.7.8 2023-07-12 18:34:15 +00:00
hrj f7568ffd5f
Merge pull request #208 from scala-steward/update/scalafmt-core-3.7.7
Update scalafmt-core to 3.7.7
2023-07-09 18:00:07 +05:30
Scala Steward 061dc82c68
Update scalafmt-core to 3.7.7 2023-07-08 20:45:06 +00:00
hrj 6ef321c418
Merge pull request #207 from scala-steward/update/scalafmt-core-3.7.6
Update scalafmt-core to 3.7.6
2023-07-06 09:09:47 +05:30
Scala Steward d3048b3b4a
Update scalafmt-core to 3.7.6 2023-07-04 17:50:54 +00:00
hrj 33fbd9a49b
Merge pull request #206 from scala-steward/update/scalafmt-core-3.7.5
Update scalafmt-core to 3.7.5
2023-07-01 10:23:01 +05:30
Scala Steward f9e626415d
Update scalafmt-core to 3.7.5 2023-06-30 19:19:09 +00:00
hrj ddb333a1df
Merge pull request #205 from scala-steward/update/scrimage-core-4.0.37
Update scrimage-core, scrimage-filters to 4.0.37
2023-06-22 11:10:23 +05:30
Scala Steward 62c0c5c363
Update scrimage-core, scrimage-filters to 4.0.37 2023-06-20 16:18:54 +00:00
hrj cff297a48f
Merge pull request #204 from scala-steward/update/scrimage-core-4.0.36
Update scrimage-core, scrimage-filters to 4.0.36
2023-06-14 08:01:52 +05:30
Scala Steward 10ca28ba07
Update scrimage-core, scrimage-filters to 4.0.36 2023-06-12 16:41:50 +00:00
hrj afab1b4803 update scala version in scripts 2023-06-02 17:34:13 +05:30
hrj 205e652e1e
Merge pull request #203 from scala-steward/update/scalafmt-core-3.7.4
Update scalafmt-core to 3.7.4
2023-06-02 17:27:53 +05:30
hrj 03ac5e5e83
Merge pull request #202 from scala-steward/update/scala3-library-3.3.0
Update scala3-library to 3.3.0
2023-06-02 17:26:50 +05:30
Scala Steward ce71407d74
Update scalafmt-core to 3.7.4 2023-05-31 19:36:09 +00:00
Scala Steward 2a33fe1e90
Update scala3-library to 3.3.0 2023-05-31 19:36:00 +00:00
hrj 9399adf2c3
Merge pull request #201 from scala-steward/update/scalafmt-core-3.7.3
Update scalafmt-core to 3.7.3
2023-04-01 07:35:30 +05:30
Scala Steward ef19bbc0c1
Update scalafmt-core to 3.7.3 2023-03-30 18:55:16 +00:00
hrj 1c95665f67
Merge pull request #200 from scala-steward/update/scrimage-core-4.0.34
Update scrimage-core, scrimage-filters to 4.0.34
2023-03-27 22:36:48 +05:30
Scala Steward 6bb9fbd7ea
Update scrimage-core, scrimage-filters to 4.0.34 2023-03-26 15:20:14 +00:00
hrj 6e6daf6c36
Merge pull request #198 from scala-steward/update/scalafmt-core-3.7.2
Update scalafmt-core to 3.7.2
2023-02-27 16:06:13 +05:30
Scala Steward daa6c49f8a
Update scalafmt-core to 3.7.2 2023-02-26 16:53:56 +00:00
hrj cb9b0d361b
Merge pull request #197 from scala-steward/update/sbt-assembly-2.1.1
Update sbt-assembly to 2.1.1
2023-02-15 06:41:07 +05:30
Scala Steward ae9163d106
Update sbt-assembly to 2.1.1 2023-02-14 16:36:59 +00:00
hrj ba21b133fc update scala to 3.2.2 2023-02-01 08:41:21 +05:30
hrj 3b0b464109
Merge pull request #196 from scala-steward/update/scala3-library-3.2.2
Update scala3-library to 3.2.2
2023-02-01 08:39:41 +05:30
Scala Steward 1663e2b306
Update scala3-library to 3.2.2 2023-01-31 18:39:59 +00:00
hrj d77bc658a0
Merge pull request #195 from scala-steward/update/scalafmt-core-3.7.1
Update scalafmt-core to 3.7.1
2023-01-26 08:04:51 +05:30
Scala Steward 33ad07c768
Update scalafmt-core to 3.7.1 2023-01-25 18:06:58 +00:00
hrj beccf4dff6 Merge remote-tracking branch 'origin/master' 2023-01-22 22:52:09 +05:30
hrj e2688f7e51
Merge pull request #194 from scala-steward/update/scalafmt-core-3.7.0
Update scalafmt-core to 3.7.0
2023-01-22 14:25:33 +05:30
Scala Steward ef4d1690e1
Update scalafmt-core to 3.7.0 2023-01-21 16:51:30 +00:00
hrj 43291222a2 README: explain podman usage and publish ports in example 2023-01-18 20:07:01 +05:30
hrj 044d39ad44
Merge pull request #191 from scala-steward/update/scrimage-core-4.0.33
Update scrimage-core, scrimage-filters to 4.0.33
2023-01-18 07:40:53 +05:30
Scala Steward b0f75677c9
Update scrimage-core, scrimage-filters to 4.0.33 2023-01-17 18:16:23 +00:00
hrj cda8bf6aa5 In Runner, use apt instead of apk 2023-01-15 08:21:03 +05:30
hrj 57b43e0f31 In Runner dockerfile use the same docker base as normal Dockerfile 2023-01-15 08:15:04 +05:30
hrj bfa2cfdc88
Merge pull request #190 from gheorghiuradu/feature/multi-platform-docker-support
Add multi platform docker support
2023-01-14 22:44:28 +05:30
gheorghiuradu 5cbb23b714
add arm platforms to build 2023-01-13 15:37:43 +02:00
gheorghiuradu a1739e5288
Update to use multi-platform images 2023-01-13 15:35:27 +02:00
hrj d5f7fdcad1
Merge pull request #189 from scala-steward/update/sbt-1.8.2
Update sbt to 1.8.2
2023-01-08 17:54:16 +05:30
Scala Steward 5950e42973
Update sbt to 1.8.2 2023-01-07 20:14:36 +00:00
hrj 59934539a7
Merge pull request #188 from scala-steward/update/sbt-assembly-2.1.0
Update sbt-assembly to 2.1.0
2022-12-11 07:39:50 +05:30
Scala Steward 399ee06b62
Update sbt-assembly to 2.1.0 2022-12-10 16:41:58 +00:00
hrj 5d7ccbb1c5 update scala version in scripts 2022-11-30 09:51:52 +05:30
hrj 25fb901e9e bump scala to 3.2.1 2022-11-30 09:49:04 +05:30
hrj dd48e9e4e7
Merge pull request #187 from scala-steward/update/sbt-scalafmt-2.5.0
Update sbt-scalafmt to 2.5.0
2022-11-15 06:20:15 +05:30
hrj 43cb991e16
Merge pull request #186 from scala-steward/update/sbt-1.8.0
Update sbt to 1.8.0
2022-11-15 06:19:48 +05:30
Scala Steward 737ebd76ae
Update sbt-scalafmt to 2.5.0 2022-11-14 22:59:30 +00:00
Scala Steward 30c978ea1c
Update sbt to 1.8.0 2022-11-14 22:59:24 +00:00
hrj 7721df414b
Merge pull request #184 from scala-steward/update/scalafmt-core-3.6.1
Update scalafmt-core to 3.6.1
2022-11-03 09:22:49 +05:30
hrj 901759e06e
Merge pull request #183 from scala-steward/update/sbt-1.7.3
Update sbt to 1.7.3
2022-11-03 09:22:06 +05:30
Scala Steward 2dab3e0638
Add 'Reformat with scalafmt 3.6.1' to .git-blame-ignore-revs 2022-11-02 18:33:05 +00:00
Scala Steward f2b19baca8
Reformat with scalafmt 3.6.1
Executed command: scalafmt --non-interactive
2022-11-02 18:33:05 +00:00
Scala Steward 56b42801d9
Update scalafmt-core to 3.6.1 2022-11-02 18:32:55 +00:00
Scala Steward 448bb5fe9f
Update sbt to 1.7.3 2022-11-02 18:32:47 +00:00
hrj fadfffafb0
Merge pull request #182 from scala-steward/update/scalafmt-core-3.6.0
Update scalafmt-core to 3.6.0
2022-10-24 10:45:01 +05:30
hrj f7d38f5f88
Merge pull request #181 from scala-steward/update/sbt-1.7.2
Update sbt to 1.7.2
2022-10-24 10:43:20 +05:30
hrj 85cfdf642c
Merge pull request #180 from scala-steward/update/json4s-jackson-4.0.6
Update json4s-jackson to 4.0.6
2022-10-24 10:42:55 +05:30
hrj 7dea087e2d
Merge pull request #179 from scala-steward/update/sbt-java-formatter-0.8.0
Update sbt-java-formatter to 0.8.0
2022-10-24 10:42:30 +05:30
hrj f7d03ac5cf
Merge branch 'master' into update/sbt-java-formatter-0.8.0 2022-10-24 10:12:59 +05:30
hrj a40b33d492
Merge pull request #178 from scala-steward/update/sbt-assembly-2.0.0
Update sbt-assembly to 2.0.0
2022-10-24 10:11:01 +05:30
Scala Steward 6eb38929d2
Update scalafmt-core to 3.6.0 2022-10-23 18:04:51 +00:00
Scala Steward a88068b865
Update sbt to 1.7.2 2022-10-23 18:04:45 +00:00
Scala Steward 5e9c9e2d5d
Update json4s-jackson to 4.0.6 2022-10-23 18:04:37 +00:00
Scala Steward f9ae1e3970
Add 'Reformat with sbt-java-formatter 0.8.0' to .git-blame-ignore-revs 2022-10-23 18:04:16 +00:00
Scala Steward 57ce691a00
Reformat with sbt-java-formatter 0.8.0
Executed command: sbt javafmtAll
2022-10-23 18:04:16 +00:00
Scala Steward 55e68d23f4
Update sbt-java-formatter to 0.8.0 2022-10-23 18:03:11 +00:00
Scala Steward b27bcc8e52
Update sbt-assembly to 2.0.0 2022-10-23 18:03:00 +00:00
hrj 6ce5bff8c5
Merge pull request #177 from scala-steward/update/sbt-scalafix-0.10.4
Update sbt-scalafix to 0.10.4
2022-10-15 07:14:49 +05:30
Scala Steward 9ef3d162f2
Update sbt-scalafix to 0.10.4 2022-10-15 00:52:24 +00:00
hrj 515782ea8b update docker image version in readme 2022-10-11 10:52:16 +05:30
hrj 70ca5673d1 fix #162: update h2 2022-10-11 10:23:01 +05:30
hrj 2a092b777e fix jar path in Runner.Dockerfile 2022-10-11 07:38:09 +05:30
hrj a2fc659eda fix jar paths in dockerfile and tests 2022-10-11 07:36:35 +05:30
hrj a020426329 update sbt in dockerfile 2022-10-11 07:36:21 +05:30
hrj 907210f229 show a message when playground is enabled 2022-10-11 07:30:58 +05:30
hrj 58c6e96dc9 fix #175: playgroundEnabled config option was not effective 2022-10-11 07:30:46 +05:30
hrj 7beecd7b80
Merge pull request #174 from scala-steward/update/scala3-library-3.2.0
Update scala3-library to 3.2.0
2022-09-08 10:13:57 +05:30
Scala Steward 2f18edef10
Update scala3-library to 3.2.0 2022-09-07 17:37:10 +00:00
hrj 76dcd1b41e
Merge pull request #173 from scala-steward/update/scrimage-core-4.0.32
Update scrimage-core, scrimage-filters to 4.0.32
2022-08-29 09:06:37 +05:30
Scala Steward 32ac8f5baa
Update scrimage-core, scrimage-filters to 4.0.32 2022-08-28 14:32:06 +00:00
hrj 5794693f51
Merge pull request #172 from scala-steward/update/scalafmt-core-3.5.9
Update scalafmt-core to 3.5.9
2022-08-12 22:13:39 +05:30
Scala Steward c02f284cc9
Update scalafmt-core to 3.5.9 2022-08-12 16:09:22 +00:00
hrj 055525bd74
Merge pull request #171 from scala-steward/update/sbt-1.7.1
Update sbt to 1.7.1
2022-07-14 18:44:49 +05:30
Scala Steward dc5d9d86ff
Update sbt to 1.7.1 2022-07-13 22:14:53 +00:00
hrj ffe3142fbf
Merge pull request #168 from scala-steward/update/scala3-library-3.1.3
Update scala3-library to 3.1.3
2022-07-10 12:50:48 +05:30
hrj 5537d907a1
Merge pull request #169 from scala-steward/update/scalafmt-core-3.5.8
Update scalafmt-core to 3.5.8
2022-07-10 12:18:34 +05:30
hrj 15dfc1576e
Merge pull request #167 from scala-steward/update/sbt-scalafix-0.10.1
Update sbt-scalafix to 0.10.1
2022-07-10 09:20:46 +05:30
Scala Steward 603e6eda22
Update scalafmt-core to 3.5.8 2022-07-09 22:40:38 +00:00
Scala Steward 3532f2ec29
Update scala3-library to 3.1.3 2022-07-09 22:40:33 +00:00
Scala Steward 0a4ca07ed4
Update sbt-scalafix to 0.10.1 2022-07-09 22:40:23 +00:00
hrj 95a7ee1710
Merge pull request #166 from scala-steward/update/scalafmt-core-3.5.3
Update scalafmt-core to 3.5.3
2022-05-15 06:53:46 +05:30
Scala Steward aa484e4bc0
Update scalafmt-core to 3.5.3 2022-05-15 00:38:11 +02:00
hrj 0549d9cfcf
Merge pull request #165 from scala-steward/update/scalafmt-core-3.5.2
Update scalafmt-core to 3.5.2
2022-05-01 06:04:55 +05:30
Scala Steward 94dddd99c0
Update scalafmt-core to 3.5.2 2022-04-30 21:44:09 +02:00
hrj 353ecaa1eb
Merge pull request #164 from scala-steward/update/scalafmt-core-3.5.1
Update scalafmt-core to 3.5.1
2022-04-17 00:20:09 +05:30
Scala Steward b402d34be8
Reformat with scalafmt 3.5.1 2022-04-16 20:42:16 +02:00
Scala Steward 37d840b365
Update scalafmt-core to 3.5.1 2022-04-16 20:42:09 +02:00
hrj a9b630724d update to scala 3.1.2 2022-04-13 07:34:11 +05:30
hrj b50df7ec2f
Merge pull request #161 from scala-steward/update/sbt-scalafix-0.10.0
Update sbt-scalafix to 0.10.0
2022-04-08 08:38:55 +05:30
Scala Steward b3c0a83594
Update sbt-scalafix to 0.10.0 2022-04-08 02:47:20 +02:00
hrj 35909261ce
Merge pull request #160 from vinceh121/patch-1
Update curl example for v2 changes
2022-04-07 21:48:01 +05:30
Vincent 073740b98b
Update curl example for v2 changes
Signed-off-by: vinceh121 <contact@vinceh121.me>
2022-04-07 16:08:40 +02:00
hrj c7726edc1c set next release version 2022-04-06 20:29:04 +05:30
hrj e35d569cbb
Merge pull request #155 from scala-steward/update/json4s-jackson-4.0.5
Update json4s-jackson to 4.0.5
2022-04-05 23:17:17 +05:30
hrj e6b09b8d33
Merge pull request #158 from JacobPozaic/master
Updated javascript example usage in README.md for 2.0.0 changes.
2022-04-05 22:48:49 +05:30
JacobPozaic a43b18587e Updated javascript example usage in README.md for 2.0.0 changes.
Signed-off-by: jacobp <jacobpozaic@gmail.com>
2022-04-05 10:30:31 -04:00
Scala Steward fb1bfbd881
Update json4s-jackson to 4.0.5 2022-04-05 14:45:59 +02:00
hrj 41afb10cb5 update version in sbt 2022-04-05 10:41:15 +05:30
hrj e1a88735e3 update test config to match newest config options 2022-04-05 10:15:21 +05:30
hrj 9b56759c80 match size in demo to size in default config 2022-04-05 10:14:28 +05:30
hrj 8df6039a7d define maxAttemptsRatio instead of maxAttempts 2022-04-05 10:13:58 +05:30
hrj a4df7a346d rename throttle to `bufferCount` in captcha fields 2022-04-05 10:13:25 +05:30
hrj 5218653f56 shadow text: center text 2022-04-05 10:12:38 +05:30
hrj 8c38ba2a21 minor cleanup 2022-04-05 09:54:03 +05:30
hrj cd6c8d790a renamed throttle config option to `bufferCount` 2022-04-05 09:53:58 +05:30
hrj 44432cbd5a Update `size` description 2022-04-04 21:47:49 +05:30
hrj c71fdbb8de
Merge pull request #153 from librecaptcha/fix98SizeParam
Respect size param
2022-04-04 21:42:11 +05:30
hrj 7ef308e556 tests: specify size parameter 2022-04-04 20:30:28 +05:30
hrj e26bd32b2f set size in test config 2022-04-04 20:28:13 +05:30
hrj cbb8abd352 functional tests: use new api path 2022-04-04 20:27:35 +05:30
hrj ba796fddf7 locust tests: use new api path 2022-04-04 19:48:28 +05:30
hrj c809872b8d Merge remote-tracking branch 'origin/master' into fix98SizeParam 2022-04-04 19:27:04 +05:30
hrj caf03d7a48 raindrops: vary length based on level, and use safe alphaNumeric characters 2022-04-04 11:13:25 +05:30
hrj 3aeb258851 rain drops: scale text to fit image size 2022-04-04 11:07:50 +05:30
hrj f8626e3670 shadow text: adapt text to size dynamically 2022-04-03 23:22:45 +05:30
hrj 83b0eb069e shadow text: dynamic kernel size 2022-04-03 23:09:45 +05:30
hrj 832053f6e9 minor, simplification 2022-04-03 23:01:40 +05:30
hrj 6480da09ff helper setRenderingHints: set antialiasing on 2022-04-03 23:01:26 +05:30
hrj 23a6a43d2d shadow text: simplify text drawing 2022-04-03 22:58:12 +05:30
hrj 7f77f819dd popping characters: adjust height to size 2022-04-03 22:49:35 +05:30
hrj bfc7174e2a FilterChallenge: use bold font 2022-04-03 16:45:53 +05:30
hrj 0c48f8fbd1 filter challenge: ensure that text fits within image width 2022-04-03 16:45:33 +05:30
hrj 595815921f
Merge pull request #152 from scala-steward/update/scalafmt-core-3.5.0
Update scalafmt-core to 3.5.0
2022-04-03 07:15:01 +05:30
hrj b33dd8adcf filter challenge: adjust filter effect based on difficult level 2022-04-02 23:18:46 +05:30
hrj d797acdcac FilterChallenge: adjust difficult based on parameter 2022-04-02 23:07:38 +05:30
hrj 444982e65f added HelperFunctions.safeAlphaNum 2022-04-02 23:06:57 +05:30
Scala Steward c396fe5c4a
Reformat with scalafmt 3.5.0 2022-04-02 19:26:52 +02:00
Scala Steward 2ee331e6b5
Update scalafmt-core to 3.5.0 2022-04-02 19:26:44 +02:00
hrj cc8addb0c7 filter challenge: scale font height based on image size 2022-04-02 22:51:45 +05:30
hrj d7c1f9a4cc handle exceptions thrown by captcha provider 2022-04-02 22:51:19 +05:30
hrj 07cce460b7
Merge pull request #151 from Korkman/patch-2
Point docker-compose.yml to "latest", add "build"
2022-03-02 17:50:52 +05:30
Korkman 7da5a5b9af
Quotes 2022-03-02 12:57:34 +01:00
Korkman 9f069e1402
Commented 2022-03-02 12:57:12 +01:00
hrj 70f8e42d93
Merge pull request #150 from Korkman/patch-1
Bump version numbers, fixes #149
2022-03-02 17:04:14 +05:30
Korkman c3eb078635
Point docker-compose.yml to "latest"
More sane to point docker-compose.yml to "latest" instead of ageing version numbers. Also added commented-out build option which should be obvious but still helps.
2022-03-02 12:25:24 +01:00
Korkman 8f34d58521
Bump version numbers, fixes #149 2022-03-02 12:19:00 +01:00
hrj 4f3bec0bc6 each challenge provider now respects the size parameter when construction image 2022-03-01 23:03:43 +05:30
hrj edd211fb52 respect size and level parameters
* Add size and level parameters to ChallengeProvider.returnChallenge()
* Add size column to challenge table
* Pass size and level parameters to all relevant calls
* Add size field to demo app
2022-03-01 22:51:38 +05:30
hrj f0659da3eb add a welcome message to root path 2022-03-01 19:11:13 +05:30
hrj c8db914cfd minor simplification 2022-03-01 17:21:30 +05:30
hrj a54947cfc2 shutdown server gracefully 2022-03-01 13:23:29 +05:30
hrj 2d9fd3c68e update h2 db to 2.1.210 2022-03-01 13:21:06 +05:30
hrj 226d3bfa74
Merge pull request #148 from librecaptcha/fix145
Fix for #145: frequent repetition of CAPTCHA challenge
2022-03-01 11:12:55 +05:30
hrj cb0c244779 in background task, divide total required by number of combinations, and create in multiple iterations
Signed-off-by: hrj <harshad.rj@gmail.com>
2022-03-01 09:37:33 +05:30
hrj 8316084ee7 create equal number of captchas for each parameter combination in background task
Signed-off-by: hrj <harshad.rj@gmail.com>
2022-03-01 09:37:33 +05:30
hrj e44a1df22e select random captchas
Signed-off-by: hrj <harshad.rj@gmail.com>
2022-03-01 09:37:33 +05:30
hrj d2a4a92463
Merge pull request #147 from scala-steward/update/scrimage-core-4.0.31
Update scrimage-core, scrimage-filters to 4.0.31
2022-02-27 15:21:03 +05:30
Scala Steward d3056699eb
Update scrimage-core, scrimage-filters to 4.0.31 2022-02-27 00:19:16 +01:00
hrj 3b6a09649d
Merge pull request #144 from librecaptcha/simplification
Simplification and minor refactoring
2022-02-24 20:48:12 +05:30
hrj 52b071d680 renamed Captcha to CaptchaManager
Signed-off-by: hrj <harshad.rj@gmail.com>
2022-02-24 20:12:58 +05:30
hrj 497b88f0d3 simplify logic for background task
Signed-off-by: hrj <harshad.rj@gmail.com>
2022-02-24 20:12:58 +05:30
hrj 6758ec3acf
Merge pull request #143 from scala-steward/update/scrimage-core-4.0.30
Update scrimage-core, scrimage-filters to 4.0.30
2022-02-24 08:41:05 +05:30
Scala Steward 10e0ff08ca
Update scrimage-core, scrimage-filters to 4.0.30 2022-02-24 00:27:06 +01:00
hrj 50b5e00ddf
Merge pull request #142 from scala-steward/update/scrimage-core-4.0.29
Update scrimage-core, scrimage-filters to 4.0.29
2022-02-23 22:12:08 +05:30
Scala Steward 34556a8e93
Update scrimage-core, scrimage-filters to 4.0.29 2022-02-23 16:28:50 +01:00
hrj 836ee0f7f1
Merge pull request #141 from scala-steward/update/scrimage-core-4.0.28
Update scrimage-core, scrimage-filters to 4.0.28
2022-02-23 13:44:52 +05:30
Scala Steward 0f8782b6d3
Update scrimage-core, scrimage-filters to 4.0.28 2022-02-23 08:24:11 +01:00
hrj 44d0464830
Merge pull request #139 from scala-steward/update/scrimage-core-4.0.27
Update scrimage-core, scrimage-filters to 4.0.27
2022-02-22 08:04:39 +05:30
Scala Steward 33a4411689
Update scrimage-core, scrimage-filters to 4.0.27 2022-02-21 20:40:24 +01:00
hrj 86e11a9075
Merge pull request #138 from scala-steward/update/sbt-assembly-1.2.0
Update sbt-assembly to 1.2.0
2022-02-13 21:06:39 +05:30
Scala Steward 25bab9eeeb
Update sbt-assembly to 1.2.0 2022-02-13 10:26:49 +01:00
hrj 7405707250
Merge pull request #137 from scala-steward/update/sbt-assembly-1.1.1
Update sbt-assembly to 1.1.1
2022-02-13 14:34:10 +05:30
Scala Steward 181bcdae0c
Update sbt-assembly to 1.1.1 2022-02-13 08:27:44 +01:00
hrj 02ac9456e1
Merge pull request #136 from scala-steward/update/scalafmt-core-3.4.3
Update scalafmt-core to 3.4.3
2022-02-12 22:55:24 +05:30
Scala Steward a74c7a8ed0
Update scalafmt-core to 3.4.3 2022-02-12 17:26:27 +01:00
hrj 9c83170bf3
Merge pull request #135 from scala-steward/update/scalafmt-core-3.4.2
Update scalafmt-core to 3.4.2
2022-02-06 19:02:54 +05:30
Scala Steward f24ede129c
Update scalafmt-core to 3.4.2 2022-02-06 12:07:47 +01:00
hrj 2f2d54a513
Merge pull request #134 from scala-steward/update/scalafmt-core-3.4.1
Update scalafmt-core to 3.4.1
2022-02-06 09:46:57 +05:30
Scala Steward 756ae8c2a7
Update scalafmt-core to 3.4.1 2022-02-05 17:51:26 +01:00
hrj 3c7c47e0d8 update lib path in docker file 2022-02-02 09:47:03 +05:30
hrj a3fbbf836b update jar file path for tests 2022-02-02 09:46:39 +05:30
hrj 300a04d47f
Merge pull request #133 from scala-steward/update/scala3-library-3.1.1
Update scala3-library to 3.1.1
2022-02-02 09:45:28 +05:30
hrj 3a7cb16286
Merge pull request #132 from scala-steward/update/sbt-1.6.2
Update sbt to 1.6.2
2022-02-02 09:42:26 +05:30
Scala Steward d0145cebe6
Update scala3-library to 3.1.1 2022-02-02 01:36:43 +01:00
Scala Steward ba9e125f9a
Update sbt to 1.6.2 2022-02-01 17:17:50 +01:00
hrj 6f22131162
Merge pull request #131 from scala-steward/update/scalafmt-core-3.4.0
Update scalafmt-core to 3.4.0
2022-01-29 20:54:28 +05:30
Scala Steward ade9a41b14
Update scalafmt-core to 3.4.0 2022-01-29 13:24:49 +01:00
hrj 8c70c53fde
Merge pull request #130 from scala-steward/update/scrimage-core-4.0.26
Update scrimage-core, scrimage-filters to 4.0.26
2022-01-28 08:35:45 +05:30
Scala Steward 250eea2e3f
Update scrimage-core, scrimage-filters to 4.0.26 2022-01-27 23:21:41 +01:00
hrj 1bf19d352e
Merge pull request #129 from scala-steward/update/json4s-jackson-4.0.4
Update json4s-jackson to 4.0.4
2022-01-23 15:58:43 +05:30
Scala Steward 925b45d6f6
Update json4s-jackson to 4.0.4 2022-01-23 08:15:38 +01:00
hrj b8eb7223e2
Merge pull request #128 from scala-steward/update/scalafmt-core-3.3.3
Update scalafmt-core to 3.3.3
2022-01-23 07:45:12 +05:30
Scala Steward 1840ec4f59
Update scalafmt-core to 3.3.3 2022-01-23 02:15:04 +01:00
hrj 7cb2d28968
Merge pull request #127 from scala-steward/update/scalafmt-core-3.3.2
Update scalafmt-core to 3.3.2
2022-01-20 10:27:02 +05:30
Scala Steward dbe0692b8b
Reformat with scalafmt 3.3.2 2022-01-20 05:36:07 +01:00
Scala Steward 46031ce2e4
Update scalafmt-core to 3.3.2 2022-01-20 05:35:57 +01:00
hrj b7ea87a629
Merge pull request #125 from scala-steward/update/sbt-scalafix-0.9.34
Update sbt-scalafix to 0.9.34
2022-01-12 07:52:55 +05:30
hrj c01139d37e
Merge pull request #124 from scala-steward/update/scrimage-core-4.0.25
Update scrimage-core, scrimage-filters to 4.0.25
2022-01-12 07:51:54 +05:30
Scala Steward a2a91d8f45
Update sbt-scalafix to 0.9.34 2022-01-11 23:20:26 +01:00
Scala Steward 85d20d8fff
Update scrimage-core, scrimage-filters to 4.0.25 2022-01-11 19:35:58 +01:00
hrj 715758ad48
Merge pull request #122 from rr83019/opt-config-param
Make config parameters optional
2022-01-09 22:42:51 +05:30
Rahul Rudragoudar 1bd342e825 Merge remote-tracking branch 'origin/opt-config-param' into opt-config-param 2022-01-09 22:34:43 +05:30
Rahul Rudragoudar 5072926bfc Refactor: lambda to fn
Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2022-01-09 22:34:33 +05:30
Rahul Rudragoudar f286ef1741 Merge remote-tracking branch 'origin/opt-config-param' into opt-config-param 2022-01-09 21:38:53 +05:30
Rahul Rudragoudar 2a01c176f7 Reconvert playgroundEnabled to bool in debug-config.json
Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2022-01-09 21:38:44 +05:30
Rahul Rudragoudar b78331819e Merge remote-tracking branch 'origin/opt-config-param' into opt-config-param 2022-01-09 21:37:22 +05:30
Rahul Rudragoudar d5cf860629 Extract and read from configField case class
Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2022-01-09 21:37:13 +05:30
Rahul Rudragoudar 71350f7105 Merge remote-tracking branch 'origin/opt-config-param' into opt-config-param 2022-01-09 01:18:57 +05:30
Rahul Rudragoudar 8e66f3fa8e WIP: Add config case class to avoid type change
Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2022-01-09 01:18:33 +05:30
hrj 8ec72ad397
Merge pull request #123 from librecaptcha/h2Update20206
Update h2 lib to 2.0.206
2022-01-08 15:30:44 +05:30
hrj a649aa7c33 Update h2 lib to 2.0.206
Signed-off-by: hrj <harshad.rj@gmail.com>
2022-01-08 10:23:34 +05:30
Rahul Rudragoudar fabd5dd7ec Convert playgroundEnabled: bool to string
Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2022-01-08 02:16:03 +05:30
Rahul Rudragoudar e1505a7573 Convert playgroundEnabled: bool to string
Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2022-01-08 02:16:03 +05:30
Rahul Rudragoudar 8e39505644 Make config parameters optional with defaults
Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2022-01-08 01:59:22 +05:30
hrj 8a87da88c0
Merge pull request #121 from librecaptcha/scala3
update jar path in docker file
2022-01-03 19:43:08 +05:30
hrj 0ed1f980dd update jar path in docker file
Signed-off-by: hrj <harshad.rj@gmail.com>
2022-01-03 19:26:27 +05:30
hrj d706d91ee1
Merge pull request #120 from librecaptcha/scala3
update to scala 3
2022-01-03 19:08:21 +05:30
hrj e78af73951 update jar path in second test
Signed-off-by: hrj <harshad.rj@gmail.com>
2022-01-03 18:56:06 +05:30
hrj 4853e6bccf change jar path in test
Signed-off-by: hrj <harshad.rj@gmail.com>
2022-01-03 18:56:06 +05:30
hrj 9688387b9b remove unsupported rules in scalafix
Signed-off-by: hrj <harshad.rj@gmail.com>
2022-01-03 18:56:06 +05:30
hrj 0b17419ccf disable unsupported option
Signed-off-by: hrj <harshad.rj@gmail.com>
2022-01-03 18:56:06 +05:30
hrj 3e99c0d38b update to scala 3
Signed-off-by: hrj <harshad.rj@gmail.com>
2022-01-03 18:56:06 +05:30
hrj fe0766320b
Merge pull request #119 from scala-steward/update/scalafmt-core-3.3.1
Update scalafmt-core to 3.3.1
2022-01-02 18:17:38 +05:30
Scala Steward ff9462e9bc
Reformat with scalafmt 3.3.1 2022-01-02 05:26:42 +01:00
Scala Steward 3122206ff7
Update scalafmt-core to 3.3.1 2022-01-02 05:26:36 +01:00
hrj 992b07c365
Merge pull request #118 from scala-steward/update/sbt-1.6.1
Update sbt to 1.6.1
2021-12-29 20:12:53 +05:30
Scala Steward 0f191e69a3
Update sbt to 1.6.1 2021-12-29 14:19:03 +01:00
hrj d4e3fb7002
Merge pull request #109 from scala-steward/update/json4s-jackson_2.13-4.0.3
Update json4s-jackson_2.13 to 4.0.3
2021-12-27 20:28:50 +05:30
hrj 4988e2e856
update assembly merge strategy to use latest conventinon
Signed-off-by: hrj <harshad.rj@gmail.com>
2021-12-27 20:19:20 +05:30
hrj 700bd2d910 assembly merge strategy that discards module-info
This is to fix this error:

deduplicate: different file contents found in the following:
[error] [snip] jackson-annotations/2.12.4/jackson-annotations-2.12.4.jar:module-info.class
[error] [snip] jackson-core/2.12.4/jackson-core-2.12.4.jar:module-info.class
2021-12-27 20:05:30 +05:30
Scala Steward f4187720d2 Update json4s-jackson_2.13 to 4.0.3 2021-12-27 20:05:30 +05:30
hrj 4fc2d4ebb0
Merge pull request #116 from rr83019/max-attempts-config
Max attempts config
2021-12-27 19:50:03 +05:30
Rahul Rudragoudar dff305ae14 Add maxAttempts in debug-config.json
Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2021-12-27 10:40:47 +05:30
hrj e17e0cab36
Merge pull request #117 from scala-steward/update/sbt-1.6.0
Update sbt to 1.6.0
2021-12-27 07:53:57 +05:30
Scala Steward 56d04ba722
Update sbt to 1.6.0 2021-12-26 22:26:09 +01:00
Rahul Rudragoudar 5e15ca6c35 Improve imports
Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2021-12-26 22:04:02 +05:30
Rahul Rudragoudar 632eb49fd3 Add config option for maxAttempts field
Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2021-12-26 22:04:02 +05:30
hrj 72cbbcde1f
Merge pull request #115 from scala-steward/update/scalafmt-core-3.3.0
Update scalafmt-core to 3.3.0
2021-12-25 18:38:01 +05:30
hrj e878353b96
Merge pull request #114 from scala-steward/update/sbt-scalafmt-2.4.6
Update sbt-scalafmt to 2.4.6
2021-12-25 18:37:26 +05:30
Scala Steward 9d0ed85f56
Update scalafmt-core to 3.3.0 2021-12-25 11:41:28 +01:00
Scala Steward 018a52a6fd
Update sbt-scalafmt to 2.4.6 2021-12-25 11:41:20 +01:00
hrj b7deb03b02
Merge pull request #113 from scala-steward/update/scalafmt-core-3.2.2
Update scalafmt-core to 3.2.2
2021-12-24 09:58:01 +05:30
Scala Steward d60eee1d13
Update scalafmt-core to 3.2.2 2021-12-24 02:08:09 +01:00
hrj 81ddfbdd4b
Merge pull request #112 from librecaptcha/updateH2-2.0.204
update H2 lib to 2.0.204
2021-12-22 10:00:42 +05:30
hrj 5e7a668016 update H2 lib to 2.0.204
Signed-off-by: hrj <harshad.rj@gmail.com>
2021-12-22 09:26:22 +05:30
hrj f08daf0026
Merge pull request #111 from scala-steward/update/sbt-1.5.8
Update sbt to 1.5.8
2021-12-21 12:20:54 +05:30
Scala Steward c78b1c96bc
Update sbt to 1.5.8 2021-12-21 05:19:25 +01:00
hrj e4e3ed413d
Merge pull request #110 from scala-steward/update/scalafmt-core-3.2.1
Update scalafmt-core to 3.2.1
2021-12-16 15:45:07 +05:30
Scala Steward 6a0ffd4ad6
Update scalafmt-core to 3.2.1 2021-12-16 09:50:30 +01:00
hrj 6cb10f409b
Merge pull request #108 from scala-steward/update/scalafmt-core-3.0.8
Update scalafmt-core to 3.0.8
2021-12-16 07:17:22 +05:30
hrj d8c2f43989
Merge pull request #107 from scala-steward/update/sbt-1.5.7
Update sbt to 1.5.7
2021-12-16 07:14:59 +05:30
hrj e3494de0bd
Merge pull request #106 from scala-steward/update/json4s-jackson_2.13-3.6.12
Update json4s-jackson_2.13 to 3.6.12
2021-12-16 07:04:48 +05:30
Scala Steward f463b487eb
Reformat with scalafmt 3.0.8 2021-12-15 22:54:41 +01:00
Scala Steward cbe26a6097
Update scalafmt-core to 3.0.8 2021-12-15 22:54:32 +01:00
Scala Steward 1c71f2ae68
Update sbt to 1.5.7 2021-12-15 22:54:24 +01:00
Scala Steward 83dcd65da3
Update json4s-jackson_2.13 to 3.6.12 2021-12-15 22:54:00 +01:00
hrj 46e084095c add shadow text sample 2021-12-10 22:12:18 +05:30
hrj 74df5a8b7b update sbt 2021-12-10 22:11:56 +05:30
hrj 0ce5e23e2f update docker tag in README and docker-compose 2021-12-10 09:52:50 +05:30
hrj 6ee4aa596d fix docker action 2021-12-10 09:28:05 +05:30
hrj 3717454f89 add tags to docker images 2021-12-10 09:27:07 +05:30
hrj b8679fb5cc protect docker actions on pull requests 2021-12-10 09:26:50 +05:30
hrj 51a1f0a710 update h2 to 2.0.202
Note that this version is NOT backwards compatible with 1.x version

Hence, we use a new DB path "captcha2". The contents in the old DB can be reused
by following instructions in
https://github.com/h2database/h2database/releases/tag/version-2.0.202
2021-12-10 00:01:35 +05:30
hrj 5f77eee1ac Allow scala 3 syntax 2021-12-09 23:25:03 +05:30
hrj ab1e09142a update scrimage version 2021-12-09 23:24:38 +05:30
hrj 529e482a17 update sbt plugins 2021-12-09 23:14:06 +05:30
hrj abc9f5440f update scala version 2021-12-09 23:13:48 +05:30
hrj 6b2d565601 update sbt version 2021-12-09 23:13:34 +05:30
hrj 928fc786cf
Merge pull request #102 from JacobPozaic/master
CORS configuration and disable playground
2021-12-09 22:00:31 +05:30
jacobp 99ee7c55b5 Added configuration to disable serving the playground webpage and configuration to set Access-Control-Allow-Origin header value on responses.
Signed-off-by: JacobPozaic <jacobpozaic@gmail.com>
2021-12-09 11:02:43 -05:00
hrj 8f606da92f
Merge pull request #96 from rr83019/image-dpi
Set Image DPI for captcha providers
2021-09-02 16:37:00 +05:30
Rahul Rudragoudar a0afba6fa5
Remove print stmts
Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2021-09-02 14:54:20 +05:30
Rahul Rudragoudar b46f6795ce
Set DPI for FilterCaptcha provider
Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2021-09-02 14:53:58 +05:30
Rahul Rudragoudar f83289514b
Rename DPISetter to PngImageWritter
Make fn static

Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2021-09-01 22:57:26 +05:30
Rahul Rudragoudar 26d86bca4c
Set DPI for captcha providers
Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2021-08-31 15:43:58 +05:30
Rahul Rudragoudar d30249a89f
Add DPI setter
Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2021-08-31 15:42:57 +05:30
hrj 1d26b76b01 added example usage for API 2021-08-04 11:45:03 +05:30
hrj 6f6c6eda66 added address to debug config 2021-05-19 20:19:23 +05:30
hrj ab9c0e6247
Merge pull request #94 from vinceh121/master
Listen address in config
2021-05-19 20:16:01 +05:30
vinceh121 bbe7c8b858
Log listen address
Signed-off-by: vinceh121 <contact@vinceh121.me>
2021-05-19 14:32:06 +02:00
vinceh121 b5a33d2e42
Listen address in config
Signed-off-by: vinceh121 <contact@vinceh121.me>
2021-05-19 14:32:02 +02:00
hrj c914484b42
Merge pull request #92 from rr83019/Config-file-path
Specify config file path
2021-05-02 20:13:17 +05:30
Rahul Rudragoudar ecff4087ad
Convert objects to classes
Update references

Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2021-05-02 16:58:14 +05:30
Rahul Rudragoudar 6f38a77c2f
Support to specify config file
Signed-off-by: Rahul Rudragoudar <rr83019@gmail.com>
2021-05-02 16:57:12 +05:30
43 changed files with 799 additions and 345 deletions

5
.git-blame-ignore-revs Normal file
View File

@ -0,0 +1,5 @@
# Scala Steward: Reformat with sbt-java-formatter 0.8.0
57ce691a00babb03e0cae03a26fe56d63fc609af
# Scala Steward: Reformat with scalafmt 3.6.1
f2b19baca828a4d88b46bc009aef6d7115e63924

3
.github/scala-steward.conf vendored Normal file
View File

@ -0,0 +1,3 @@
# If true, Scala Steward will sign off all commits (e.g. `git --signoff`).
# Default: false
signoffCommits = true

View File

@ -16,6 +16,7 @@ jobs:
uses: actions/setup-java@v1
with:
java-version: 1.11
- uses: sbt/setup-sbt@v1
- name: Run tests
run: sbt test assembly
- name: Run linter

View File

@ -3,6 +3,8 @@ name: Update docker image
on:
push:
branches: [ master ]
tags:
- 'v*'
jobs:
build:
@ -20,7 +22,20 @@ jobs:
- name: Assemble Jar
run: sbt assembly
-
name: Docker meta
id: meta
uses: docker/metadata-action@v3
with:
images: librecaptcha/lc-core
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Login to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
@ -36,8 +51,13 @@ jobs:
with:
context: ./
file: ./Runner.Dockerfile
push: true
tags: librecaptcha/lc-core:latest
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: |
linux/amd64
linux/arm64
linux/arm/v7
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}

View File

@ -1,8 +1,5 @@
rules=[
ExplicitResultTypes,
RemoveUnused,
DisableSyntax,
LeakingImplicitClassVal,
NoValInForComprehension,
ProcedureSyntax
]

View File

@ -1,2 +1,3 @@
version=2.5.2
version="3.8.3"
maxColumn = 120
runner.dialect = scala3

View File

@ -1,9 +1,10 @@
FROM adoptopenjdk/openjdk16:alpine AS base-builder
ARG SBT_VERSION=1.3.13
RUN apk add --no-cache bash
FROM eclipse-temurin:17-jre-jammy AS base-builder
ARG SBT_VERSION=1.7.1
ENV JAVA_HOME="/usr/lib/jvm/default-jvm/"
ENV PATH=$PATH:${JAVA_HOME}/bin
RUN \
apt update && \
apt install -y wget && \
wget -O sbt-$SBT_VERSION.tgz https://github.com/sbt/sbt/releases/download/v$SBT_VERSION/sbt-$SBT_VERSION.tgz && \
tar -xzvf sbt-$SBT_VERSION.tgz && \
rm sbt-$SBT_VERSION.tgz
@ -22,15 +23,15 @@ FROM sbt-builder as builder
COPY src/ src/
RUN sbt assembly
FROM adoptopenjdk/openjdk16:alpine-jre AS base-core
FROM eclipse-temurin:17-jre-jammy AS base-core
ENV JAVA_HOME="/usr/lib/jvm/default-jvm/"
RUN apk add --update ttf-dejavu
RUN apt update && apt install -y fonts-dejavu
ENV PATH=$PATH:${JAVA_HOME}/bin
FROM base-core
WORKDIR /lc-core
COPY --from=builder /build/target/scala-2.13/LibreCaptcha.jar .
COPY --from=builder /build/target/scala-3.6.2/LibreCaptcha.jar .
RUN mkdir data/
EXPOSE 8888

View File

@ -47,18 +47,25 @@ docker-compose up
Using `docker`:
```
docker run -v lcdata:/lc-core/data librecaptcha/lc-core:latest
docker run -p=8888:8888 -v ./lcdata:/lc-core/data librecaptcha/lc-core:2.0
```
A default `config.json` is automatically created in the mounted volume.
The above commands should work with `podman` as well, if docker.io registry is pre-configured. Otherwise,
you can manually specify the repository like so:
```
podman run -p=8888:8888 -v ./lcdata:/lc-core/data docker.io/librecaptcha/lc-core:2.0
```
## Quick test
Open [localhost:8888/demo/index.html](http://localhost:8888/demo/index.html) in browser.
Alternatively, on the command line, try:
```
> $ curl -d '{"media":"image/png","level":"easy","input_type":"text"}' localhost:8888/v1/captcha
> $ curl -d '{"media":"image/png","level":"easy","input_type":"text","size":"350x100"}' localhost:8888/v2/captcha
{"id":"3bf928ce-a1e7-4616-b34f-8252d777855d"}
> $ curl "localhost:8888/v1/media?id=3bf928ce-a1e7-4616-b34f-8252d777855d" -o sample.png
@ -91,6 +98,11 @@ create CAPTCHAs that suit their application and audience, with matching themes a
And, the more the variety of CAPTCHAS, the harder it is for bots to crack CAPTCHAs.
## Sample CAPTCHAs
These are included in this server.
### ShadowText
![ShadowText Sample](./samples/shadowText.png)
### FilterCaptcha
@ -115,6 +127,9 @@ If a sufficient number of users agree on their answer to the unknown word, it is
***
## HTTP API
The service can be accessed using a simple HTTP API.
### - `/v1/captcha`: `POST`
- Parameters:
- `level`: `String` -
@ -131,12 +146,12 @@ If a sufficient number of users agree on their answer to the unknown word, it is
- image/png
- image/gif
- (More to come)
- `size`: `Map` -
The dimensions of a captcha (Optional). It needs two more fields nested in this parameter
- `height`: `Int`
- `width`: `Int`
- `size`: String -
The dimensions of a captcha. It needs to be a string in the format `"widthxheight"` in pixels, and will be matched
with the `allowedSizes` config setting. Example: `size: "450x200"` which requests an image of width 450 and height
200 pixels.
- Return type:
- Returns:
- `id`: `String` - The uuid of the captcha generated
@ -144,7 +159,7 @@ If a sufficient number of users agree on their answer to the unknown word, it is
- Parameters:
- `id`: `String` - The uuid of the captcha
- Return type:
- Returns:
- `image`: `Array[Byte]` - The requested media as bytes
@ -153,12 +168,46 @@ If a sufficient number of users agree on their answer to the unknown word, it is
- `id`: `String` - The uuid of the captcha that needs to be solved
- `answer`: `String` - The answer to the captcha that needs to be validated
- Return Type:
- Returns:
- `result`: `String` - The result after validation/checking of the answer
- True - If the answer is correct
- False - If the answer is incorrect
- Expired - If the time limit to solve the captcha exceeds
## Example usage
In javascript:
```js
const resp = await fetch("/v2/captcha", {
method: 'POST',
body: JSON.stringify({level: "easy", media: "image/png", "input_type" : "text", size: "350x100"})
})
const respJson = await resp.json();
let captchaId = null;
if (resp.ok) {
// The CAPTCHA can be displayed using the data in respJson.
console.log(respJson);
// Store the id somewhere so that it can be used later for answer verification
captchaId = respJson.id;
} else {
console.err(respJson);
}
// When user submits an answer it can be sent to the server for verification thusly:
const resp = await fetch("/v2/answer", {
method: 'POST',
body: JSON.stringify({id: captchaId, answer: "user input"})
});
const respJson = await resp.json();
console.log(respJson.result);
```
***
## Roadmap

View File

@ -1,12 +1,12 @@
FROM adoptopenjdk/openjdk16:alpine-jre AS base-core
FROM eclipse-temurin:17-jre-jammy AS base-core
ENV JAVA_HOME="/usr/lib/jvm/default-jvm/"
RUN apk add --update ttf-dejavu
RUN apt update && apt install -y fonts-dejavu
ENV PATH=$PATH:${JAVA_HOME}/bin
FROM base-core
RUN mkdir /lc-core
COPY target/scala-2.13/LibreCaptcha.jar /lc-core
COPY target/scala-3.6.2/LibreCaptcha.jar /lc-core
WORKDIR /lc-core
RUN mkdir data/

View File

@ -2,23 +2,23 @@ lazy val root = (project in file(".")).settings(
inThisBuild(
List(
organization := "com.example",
scalaVersion := "2.13.5",
version := "0.1.0-SNAPSHOT",
scalaVersion := "3.6.2",
version := "0.2.1-snapshot",
semanticdbEnabled := true,
semanticdbVersion := scalafixSemanticdb.revision,
scalafixScalaBinaryVersion := "2.13"
semanticdbVersion := scalafixSemanticdb.revision
// This is apparently not supported on Scala 3 currently
// scalafixScalaBinaryVersion := "3.1"
)
),
name := "LibreCaptcha",
libraryDependencies += "com.sksamuel.scrimage" % "scrimage-core" % "4.0.12",
libraryDependencies += "com.sksamuel.scrimage" % "scrimage-filters" % "4.0.12",
libraryDependencies += "org.json4s" % "json4s-jackson_2.13" % "3.6.11"
libraryDependencies += "com.sksamuel.scrimage" % "scrimage-core" % "4.3.0",
libraryDependencies += "com.sksamuel.scrimage" % "scrimage-filters" % "4.3.0",
libraryDependencies += "org.json4s" %% "json4s-jackson" % "4.0.7"
)
Compile / unmanagedResourceDirectories += { baseDirectory.value / "lib" }
scalacOptions ++= List(
"-Yrangepos",
"-Ywarn-unused",
"-deprecation"
)
javacOptions += "-g:none"
@ -28,4 +28,12 @@ assembly / mainClass := Some("lc.LCFramework")
Compile / run / mainClass := Some("lc.LCFramework")
assembly / assemblyJarName := "LibreCaptcha.jar"
ThisBuild / assemblyMergeStrategy := {
case PathList("module-info.class") => MergeStrategy.discard
case x if x.endsWith("/module-info.class") => MergeStrategy.discard
case x =>
val oldStrategy = (ThisBuild / assemblyMergeStrategy).value
oldStrategy(x)
}
run / fork := true

View File

@ -4,6 +4,8 @@ services:
lc-core:
container_name: "libre-captcha"
image: librecaptcha/lc-core:latest
# Comment "image" & uncomment "build" if you intend to build from source
#build: .
volumes:
- "./docker-data:/lc-core/data"
ports:

Binary file not shown.

BIN
lib/h2-2.1.214.jar Normal file

Binary file not shown.

View File

@ -1 +1 @@
sbt.version=1.5.0
sbt.version=1.10.6

View File

@ -1,4 +1,4 @@
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.27")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.2")
addSbtPlugin("com.lightbend.sbt" % "sbt-java-formatter" % "0.6.0")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.15.0")
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.13.0")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.2")
addSbtPlugin("com.lightbend.sbt" % "sbt-java-formatter" % "0.8.0")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.0")

BIN
samples/shadowText.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -1,16 +1,16 @@
package lc.captchas;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Map;
import java.util.List;
import java.util.Map;
import lc.captchas.interfaces.Challenge;
import lc.captchas.interfaces.ChallengeProvider;
import lc.misc.HelperFunctions;
import lc.misc.PngImageWriter;
public class FontFunCaptcha implements ChallengeProvider {
@ -58,9 +58,10 @@ public class FontFunCaptcha implements ChallengeProvider {
return null;
}
private byte[] fontFun(String captchaText, String level, String path) {
private byte[] fontFun(
final int width, final int height, String captchaText, String level, String path) {
String[] colors = {"#f68787", "#f8a978", "#f1eb9a", "#a4f6a5"};
BufferedImage img = new BufferedImage(350, 100, BufferedImage.TYPE_INT_RGB);
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = img.createGraphics();
for (int i = 0; i < captchaText.length(); i++) {
Font font = loadCustomFont(level, path);
@ -74,17 +75,21 @@ public class FontFunCaptcha implements ChallengeProvider {
graphics2D.dispose();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ImageIO.write(img, "png", baos);
PngImageWriter.write(baos, img);
} catch (Exception e) {
e.printStackTrace();
}
return baos.toByteArray();
}
public Challenge returnChallenge() {
public Challenge returnChallenge(String level, String size) {
String secret = HelperFunctions.randomString(7);
final int[] size2D = HelperFunctions.parseSize2D(size);
final int width = size2D[0];
final int height = size2D[1];
String path = "./lib/fonts/";
return new Challenge(fontFun(secret, "medium", path), "image/png", secret.toLowerCase());
return new Challenge(
fontFun(width, height, secret, "medium", path), "image/png", secret.toLowerCase());
}
public boolean checkAnswer(String secret, String answer) {

View File

@ -1,51 +1,51 @@
package lc.captchas;
import java.awt.Font;
import java.awt.RenderingHints;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.IntStream;
import java.util.LinkedList;
import java.util.List;
import javax.imageio.stream.MemoryCacheImageOutputStream;
import java.io.ByteArrayOutputStream;
import lc.captchas.interfaces.Challenge;
import lc.captchas.interfaces.ChallengeProvider;
import lc.misc.HelperFunctions;
import lc.misc.GifSequenceWriter;
import lc.misc.HelperFunctions;
public class PoppingCharactersCaptcha implements ChallengeProvider {
private final Font font = new Font("Arial", Font.ROMAN_BASELINE, 48);
private final int width = 250;
private final int height = 100;
private Integer[] computeOffsets(final String text) {
private int[] computeOffsets(
final Font font, final int width, final int height, final String text) {
final var img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
final var graphics2D = img.createGraphics();
final var frc = graphics2D.getFontRenderContext();
final var advances = new LinkedList<Integer>();
final var advances = new int[text.length() + 1];
final var spacing = font.getStringBounds(" ", frc).getWidth() / 3;
var currX = 0;
for (int i = 0; i < text.length(); i++) {
final var c = text.charAt(i);
advances.add(currX);
advances[i] = currX;
currX += font.getStringBounds(String.valueOf(c), frc).getWidth();
currX += spacing;
};
}
;
advances[text.length()] = currX;
graphics2D.dispose();
return advances.toArray(new Integer[]{});
return advances;
}
private BufferedImage makeImage(final Consumer<Graphics2D> f) {
private BufferedImage makeImage(
final Font font, final int width, final int height, final Consumer<Graphics2D> f) {
final var img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
final var graphics2D = img.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
graphics2D.setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
graphics2D.setFont(font);
f.accept(graphics2D);
graphics2D.dispose();
@ -56,23 +56,42 @@ public class PoppingCharactersCaptcha implements ChallengeProvider {
return HelperFunctions.randomNumber(-2, +2);
}
private byte[] gifCaptcha(final String text) {
private byte[] gifCaptcha(final int width, final int height, final String text) {
try {
final var fontHeight = (int) (height * 0.5);
final Font font = new Font("Arial", Font.ROMAN_BASELINE, fontHeight);
final var byteArrayOutputStream = new ByteArrayOutputStream();
final var output = new MemoryCacheImageOutputStream(byteArrayOutputStream);
final var writer = new GifSequenceWriter(output, 1, 900, true);
final var advances = computeOffsets(text);
final var advances = computeOffsets(font, width, height, text);
final var expectedWidth = advances[advances.length - 1];
final var scale = width / (float) expectedWidth;
final var prevColor = Color.getHSBColor(0f, 0f, 0.1f);
IntStream.range(0, text.length()).forEach(i -> {
final var color = Color.getHSBColor(HelperFunctions.randomNumber(0, 100)/100.0f, 0.6f, 1.0f);
final var nextImage = makeImage((g) -> {
IntStream.range(0, text.length())
.forEach(
i -> {
final var color =
Color.getHSBColor(HelperFunctions.randomNumber(0, 100) / 100.0f, 0.6f, 1.0f);
final var nextImage =
makeImage(
font,
width,
height,
(g) -> {
g.scale(scale, 1);
if (i > 0) {
final var prevI = (i - 1) % text.length();
g.setColor(prevColor);
g.drawString(String.valueOf(text.charAt(prevI)), advances[prevI] + jitter(), 45 + jitter());
g.drawString(
String.valueOf(text.charAt(prevI)),
advances[prevI] + jitter(),
fontHeight * 1.1f + jitter());
}
g.setColor(color);
g.drawString(String.valueOf(text.charAt(i)), advances[i] + jitter(), 45 + jitter());
g.drawString(
String.valueOf(text.charAt(i)),
advances[i] + jitter(),
fontHeight * 1.1f + jitter());
});
try {
writer.writeToSequence(nextImage);
@ -100,9 +119,12 @@ public class PoppingCharactersCaptcha implements ChallengeProvider {
"supportedInputType", List.of("text"));
}
public Challenge returnChallenge() {
public Challenge returnChallenge(String level, String size) {
final var secret = HelperFunctions.randomString(6);
return new Challenge(gifCaptcha(secret), "image/gif", secret.toLowerCase());
final int[] size2D = HelperFunctions.parseSize2D(size);
final int width = size2D[0];
final int height = size2D[1];
return new Challenge(gifCaptcha(width, height, secret), "image/gif", secret.toLowerCase());
}
public boolean checkAnswer(String secret, String answer) {

View File

@ -1,21 +1,18 @@
package lc.captchas;
import javax.imageio.ImageIO;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Color;
import java.awt.Font;
import java.awt.font.TextLayout;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.ByteArrayOutputStream;
import java.util.Map;
import java.util.List;
import lc.misc.HelperFunctions;
import java.util.Map;
import lc.captchas.interfaces.Challenge;
import lc.captchas.interfaces.ChallengeProvider;
import lc.misc.HelperFunctions;
import lc.misc.PngImageWriter;
public class ShadowTextCaptcha implements ChallengeProvider {
@ -38,44 +35,58 @@ public class ShadowTextCaptcha implements ChallengeProvider {
return answer.toLowerCase().equals(secret);
}
private byte[] shadowText(String text) {
BufferedImage img = new BufferedImage(350, 100, BufferedImage.TYPE_INT_RGB);
Font font = new Font("Arial", Font.ROMAN_BASELINE, 48);
Graphics2D graphics2D = img.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics2D.setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
private float[] makeKernel(int size) {
final int N = size * size;
final float weight = 1.0f / (N);
final float[] kernel = new float[N];
java.util.Arrays.fill(kernel, weight);
return kernel;
};
TextLayout textLayout = new TextLayout(text, font, graphics2D.getFontRenderContext());
private byte[] shadowText(final int width, final int height, String text) {
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
final int fontHeight = (int) (height * 0.5f);
Font font = new Font("Arial", Font.PLAIN, fontHeight);
Graphics2D graphics2D = img.createGraphics();
HelperFunctions.setRenderingHints(graphics2D);
graphics2D.setPaint(Color.WHITE);
graphics2D.fillRect(0, 0, 350, 100);
graphics2D.fillRect(0, 0, width, height);
graphics2D.setPaint(Color.BLACK);
textLayout.draw(graphics2D, 15, 50);
graphics2D.setFont(font);
final var stringWidth = graphics2D.getFontMetrics().stringWidth(text);
final var padding = (stringWidth > width) ? 0 : (width - stringWidth) / 2;
final var scaleX = (stringWidth > width) ? width / ((double) stringWidth) : 1d;
graphics2D.scale(scaleX, 1d);
graphics2D.drawString(text, padding, fontHeight * 1.1f);
graphics2D.dispose();
float[] kernel = {
1f / 9f, 1f / 9f, 1f / 9f,
1f / 9f, 1f / 9f, 1f / 9f,
1f / 9f, 1f / 9f, 1f / 9f
};
ConvolveOp op = new ConvolveOp(new Kernel(3, 3, kernel), ConvolveOp.EDGE_NO_OP, null);
final int kernelSize = (int) Math.ceil((Math.min(width, height) / 50.0));
ConvolveOp op =
new ConvolveOp(
new Kernel(kernelSize, kernelSize, makeKernel(kernelSize)),
ConvolveOp.EDGE_NO_OP,
null);
BufferedImage img2 = op.filter(img, null);
Graphics2D g2d = img2.createGraphics();
HelperFunctions.setRenderingHints(g2d);
g2d.setPaint(Color.WHITE);
textLayout.draw(g2d, 13, 50);
g2d.scale(scaleX, 1d);
g2d.setFont(font);
g2d.drawString(text, padding - kernelSize, fontHeight * 1.1f);
g2d.dispose();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ImageIO.write(img2, "png", baos);
PngImageWriter.write(baos, img2);
} catch (Exception e) {
e.printStackTrace();
}
return baos.toByteArray();
}
public Challenge returnChallenge() {
public Challenge returnChallenge(String level, String size) {
String secret = HelperFunctions.randomString(6);
return new Challenge(shadowText(secret), "image/png", secret.toLowerCase());
final int[] size2D = HelperFunctions.parseSize2D(size);
final int width = size2D[0];
final int height = size2D[1];
return new Challenge(shadowText(width, height, secret), "image/png", secret.toLowerCase());
}
}

View File

@ -1,12 +1,12 @@
package lc.captchas.interfaces;
import java.util.Map;
import java.util.List;
import java.util.Map;
public interface ChallengeProvider {
public String getId();
public Challenge returnChallenge();
public Challenge returnChallenge(String level, String size);
public boolean checkAnswer(String secret, String answer);

View File

@ -3,12 +3,12 @@
package lc.misc;
import javax.imageio.*;
import javax.imageio.metadata.*;
import javax.imageio.stream.*;
import java.awt.image.*;
import java.io.*;
import java.util.Iterator;
import javax.imageio.*;
import javax.imageio.metadata.*;
import javax.imageio.stream.*;
public class GifSequenceWriter {
protected ImageWriter gifWriter;

View File

@ -7,11 +7,18 @@ public class HelperFunctions {
private static Random random = new Random();
synchronized public static void setSeed(long seed){
public static synchronized void setSeed(long seed) {
random.setSeed(seed);
}
public static int[] parseSize2D(final String size) {
final String[] fields = size.split("x");
final int[] result = {Integer.parseInt(fields[0]), Integer.parseInt(fields[1])};
return result;
}
public static void setRenderingHints(Graphics2D g2d) {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(
@ -23,7 +30,8 @@ public class HelperFunctions {
public static final String safeNumbers = "23456789";
public static final String allNumbers = safeNumbers + "10";
public static final String specialCharacters = "$#%@&?";
public static final String safeCharacters = safeAlphabets + safeNumbers + specialCharacters;
public static final String safeAlphaNum = safeAlphabets + safeNumbers;
public static final String safeCharacters = safeAlphaNum + specialCharacters;
public static String randomString(final int n) {
return randomString(n, safeCharacters);
@ -38,12 +46,11 @@ public class HelperFunctions {
return stringBuilder.toString();
}
synchronized public static int randomNumber(int min, int max) {
public static synchronized int randomNumber(int min, int max) {
return random.nextInt((max - min) + 1) + min;
}
synchronized public static int randomNumber(int bound) {
public static synchronized int randomNumber(int bound) {
return random.nextInt(bound);
}
}

View File

@ -0,0 +1,68 @@
package lc.misc;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.ImageOutputStream;
public class PngImageWriter {
static final int DPI = 245;
static final double INCH_2_CM = 2.54;
public static void write(ByteArrayOutputStream boas, BufferedImage gridImage) throws IOException {
final String formatName = "png";
for (Iterator<ImageWriter> iw = ImageIO.getImageWritersByFormatName(formatName);
iw.hasNext(); ) {
ImageWriter writer = iw.next();
ImageWriteParam writeParam = writer.getDefaultWriteParam();
ImageTypeSpecifier typeSpecifier =
ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam);
if (metadata.isReadOnly() || !metadata.isStandardMetadataFormatSupported()) {
continue;
}
setDPIMeta(metadata);
final ImageOutputStream stream = ImageIO.createImageOutputStream(boas);
try {
writer.setOutput(stream);
writer.write(metadata, new IIOImage(gridImage, null, metadata), writeParam);
} finally {
stream.close();
}
break;
}
}
private static void setDPIMeta(IIOMetadata metadata) throws IIOInvalidTreeException {
// for PNG, it's dots per millimeter
double dotsPerMilli = 1.0 * DPI / 10 / INCH_2_CM;
IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
horiz.setAttribute("value", Double.toString(dotsPerMilli));
IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
vert.setAttribute("value", Double.toString(dotsPerMilli));
IIOMetadataNode dim = new IIOMetadataNode("Dimension");
dim.appendChild(horiz);
dim.appendChild(vert);
IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
root.appendChild(dim);
metadata.mergeTree("javax_imageio_1.0", root);
}
}

View File

@ -3,21 +3,21 @@
package org.limium.picoserve;
import java.net.InetSocketAddress;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.LinkedList;
import java.util.concurrent.Executor;
import java.util.regex.Pattern;
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Collectors;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpExchange;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public final class Server {
private final HttpServer server;

View File

@ -20,9 +20,10 @@
const levelInput = document.getElementById("levelInput").value
const mediaInput = document.getElementById("mediaInput").value
const typeInput = document.getElementById("typeInput").value
fetch("/v1/captcha", {
const sizeInput = document.getElementById("sizeInput").value
fetch("/v2/captcha", {
method: 'POST',
body: JSON.stringify({level: levelInput, media: mediaInput, "input_type" : typeInput})
body: JSON.stringify({level: levelInput, media: mediaInput, "input_type" : typeInput, "size": sizeInput})
}).then(async function(resp) {
const respJson = await resp.json()
if (resp.ok) {
@ -30,7 +31,7 @@
const resultDiv = document.getElementById("result")
const result = `
<p>Id: ${id}</p>
<p><img src="/v1/media?id=${id}" /> </p>
<p><img src="/v2/media?id=${id}" /> </p>
<input type="text" id="answerInput" />
<button onClick="submitAnswer('${id}')">Submit</button>
<div id="answerResult" />
@ -43,7 +44,7 @@
}
async function submitAnswer(id) {
const ans = document.getElementById("answerInput").value;
const resp = await fetch("/v1/answer", {
const resp = await fetch("/v2/answer", {
method: 'POST',
body: JSON.stringify({id: id, answer: ans})
})
@ -70,6 +71,10 @@
<span>Input Type</span>
<input type="text" id="typeInput" value="text" />
</div>
<div class="inputGroup">
<span>Input Size</span>
<input type="text" id="sizeInput" value="350x100" />
</div>
<div class="inputGroup">
<button onClick="loadCaptcha()">Get New CAPTCHA</button>
</div>

View File

@ -1,27 +1,53 @@
package lc
import lc.core.CaptchaProviders
import lc.core.{CaptchaProviders, CaptchaManager, Config}
import lc.server.Server
import lc.background.BackgroundTask
import lc.core.Config
import lc.database.Statements
object LCFramework {
def main(args: scala.Array[String]): Unit = {
val backgroundTask = new BackgroundTask(
throttle = Config.throttle,
timeLimit = Config.captchaExpiryTimeLimit
val configFilePath = if (args.length > 0) {
args(0)
} else {
"data/config.json"
}
val config = new Config(configFilePath)
Statements.maxAttempts = config.maxAttempts
val captchaProviders = new CaptchaProviders(config = config)
val captchaManager = new CaptchaManager(config = config, captchaProviders = captchaProviders)
val backgroundTask = new BackgroundTask(config = config, captchaManager = captchaManager)
backgroundTask.beginThread(delay = config.threadDelay)
val server = new Server(
address = config.address,
port = config.port,
captchaManager = captchaManager,
playgroundEnabled = config.playgroundEnabled,
corsHeader = config.corsHeader
)
backgroundTask.beginThread(delay = Config.threadDelay)
val server = new Server(port = Config.port)
Runtime.getRuntime.addShutdownHook(new Thread {
override def run(): Unit = {
println("Shutting down gracefully...")
backgroundTask.shutdown()
}
})
server.start()
}
}
object MakeSamples {
def main(args: scala.Array[String]): Unit = {
val samples = CaptchaProviders.generateChallengeSamples()
samples.foreach {
case (key, sample) =>
val configFilePath = if (args.length > 0) {
args(0)
} else {
"data/config.json"
}
val config = new Config(configFilePath)
val captchaProviders = new CaptchaProviders(config = config)
val samples = captchaProviders.generateChallengeSamples()
samples.foreach { case (key, sample) =>
val extensionMap = Map("image/png" -> "png", "image/gif" -> "gif")
println(key + ": " + sample)

View File

@ -2,50 +2,89 @@ package lc.background
import lc.database.Statements
import java.util.concurrent.{ScheduledThreadPoolExecutor, TimeUnit}
import lc.core.{Captcha, Config}
import lc.core.{CaptchaManager, Config}
import lc.core.{Parameters, Size}
import lc.misc.HelperFunctions
class BackgroundTask(throttle: Int, timeLimit: Int) {
class BackgroundTask(config: Config, captchaManager: CaptchaManager) {
private val task = new Runnable {
def run(): Unit = {
try {
val mapIdGCPstmt = Statements.tlStmts.get.mapIdGCPstmt
mapIdGCPstmt.setInt(1, timeLimit)
mapIdGCPstmt.setInt(1, config.captchaExpiryTimeLimit)
mapIdGCPstmt.executeUpdate()
val challengeGCPstmt = Statements.tlStmts.get.challengeGCPstmt
challengeGCPstmt.executeUpdate()
val imageNum = Statements.tlStmts.get.getCountChallengeTable.executeQuery()
var throttleIn = (throttle * 1.1).toInt
if (imageNum.next())
throttleIn = (throttleIn - imageNum.getInt("total"))
while (0 < throttleIn) {
Captcha.generateChallenge(getRandomParam())
throttleIn -= 1
val allCombinations = allParameterCombinations()
val requiredCountPerCombination = Math.max(1, (config.bufferCount * 1.01) / allCombinations.size).toInt
for (param <- allCombinations) {
if (!shutdownInProgress) {
val countExisting = captchaManager.getCount(param).getOrElse(0)
val countRequired = requiredCountPerCombination - countExisting
if (countRequired > 0) {
val countCreate = Math.min(1.0 + requiredCountPerCombination / 10.0, countRequired).toInt
println(s"Creating $countCreate of $countRequired captchas for $param")
for (i <- 0 until countCreate) {
if (!shutdownInProgress) {
captchaManager.generateChallenge(param)
}
}
}
}
}
} catch { case exception: Exception => println(exception) }
}
}
private def allParameterCombinations(): List[Parameters] = {
(config.captchaConfig).flatMap { captcha =>
(captcha.allowedLevels).flatMap { level =>
(captcha.allowedMedia).flatMap { media =>
(captcha.allowedInputType).flatMap { inputType =>
(captcha.allowedSizes).map { size =>
Parameters(level, media, inputType, size)
}
}
}
}
}
}
private def getRandomParam(): Parameters = {
val captcha = pickRandom(Config.captchaConfig)
val captcha = pickRandom(config.captchaConfig)
val level = pickRandom(captcha.allowedLevels)
val media = pickRandom(captcha.allowedMedia)
val inputType = pickRandom(captcha.allowedInputType)
val size = pickRandom(captcha.allowedSizes)
Parameters(level, media, inputType, Some(Size(0, 0)))
Parameters(level, media, inputType, size)
}
private def pickRandom[T](list: List[T]): T = {
list(HelperFunctions.randomNumber(list.size))
}
private val ex = new ScheduledThreadPoolExecutor(1)
def beginThread(delay: Int): Unit = {
val ex = new ScheduledThreadPoolExecutor(1)
ex.scheduleWithFixedDelay(task, 1, delay, TimeUnit.SECONDS)
}
@volatile var shutdownInProgress = false
def shutdown(): Unit = {
println(" Shutting down background task...")
shutdownInProgress = true
ex.shutdown()
println(" Finished Shutting background task")
println(" Shutting down DB...")
Statements.tlStmts.get.shutdown.execute()
println(" Finished shutting down db")
}
}

View File

@ -1,6 +1,5 @@
package lc.captchas
import javax.imageio.ImageIO
import java.awt.Color
import java.awt.Font
import java.awt.font.TextLayout
@ -12,8 +11,11 @@ import java.util.List
import lc.misc.HelperFunctions
import lc.captchas.interfaces.Challenge
import lc.captchas.interfaces.ChallengeProvider
import lc.misc.PngImageWriter
/** This captcha is only for debugging purposes. It creates very simple captchas that are deliberately easy to solve with OCR engines */
/** This captcha is only for debugging purposes. It creates very simple captchas that are deliberately easy to solve
* with OCR engines
*/
class DebugCaptcha extends ChallengeProvider {
def getId(): String = {
@ -26,9 +28,12 @@ class DebugCaptcha extends ChallengeProvider {
def supportedParameters(): Map[String, List[String]] = {
Map.of(
"supportedLevels", List.of("debug"),
"supportedMedia", List.of("image/png"),
"supportedInputType", List.of("text")
"supportedLevels",
List.of("debug"),
"supportedMedia",
List.of("image/png"),
"supportedInputType",
List.of("text")
)
}
@ -40,20 +45,20 @@ class DebugCaptcha extends ChallengeProvider {
matches
}
private def simpleText(text: String): Array[Byte] = {
val img = new BufferedImage(350, 100, BufferedImage.TYPE_INT_RGB)
private def simpleText(width: Int, height: Int, text: String): Array[Byte] = {
val img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
val font = new Font("Arial", Font.ROMAN_BASELINE, 56)
val graphics2D = img.createGraphics()
val textLayout = new TextLayout(text, font, graphics2D.getFontRenderContext())
HelperFunctions.setRenderingHints(graphics2D)
graphics2D.setPaint(Color.WHITE)
graphics2D.fillRect(0, 0, 350, 100)
graphics2D.fillRect(0, 0, width, height)
graphics2D.setPaint(Color.BLACK)
textLayout.draw(graphics2D, 15, 50)
graphics2D.dispose()
val baos = new ByteArrayOutputStream()
try {
ImageIO.write(img, "png", baos)
PngImageWriter.write(baos, img);
} catch {
case e: Exception =>
e.printStackTrace()
@ -61,8 +66,11 @@ class DebugCaptcha extends ChallengeProvider {
baos.toByteArray()
}
def returnChallenge(): Challenge = {
def returnChallenge(level: String, size: String): Challenge = {
val secret = HelperFunctions.randomString(6, HelperFunctions.safeAlphabets)
new Challenge(simpleText(secret), "image/png", secret.toLowerCase())
val size2D = HelperFunctions.parseSize2D(size)
val width = size2D(0)
val height = size2D(1)
new Challenge(simpleText(width, height, secret), "image/png", secret.toLowerCase())
}
}

View File

@ -8,6 +8,9 @@ import java.awt.Color
import lc.captchas.interfaces.ChallengeProvider
import lc.captchas.interfaces.Challenge
import java.util.{List => JavaList, Map => JavaMap}
import java.io.ByteArrayOutputStream
import lc.misc.PngImageWriter
import lc.misc.HelperFunctions
class FilterChallenge extends ChallengeProvider {
def getId = "FilterChallenge"
@ -18,30 +21,48 @@ class FilterChallenge extends ChallengeProvider {
def supportedParameters(): JavaMap[String, JavaList[String]] = {
JavaMap.of(
"supportedLevels",JavaList.of("medium", "hard"),
"supportedMedia", JavaList.of("image/png"),
"supportedInputType", JavaList.of("text")
"supportedLevels",
JavaList.of("medium", "hard"),
"supportedMedia",
JavaList.of("image/png"),
"supportedInputType",
JavaList.of("text")
)
}
def returnChallenge(): Challenge = {
val filterTypes = List(new FilterType1, new FilterType2)
private val filterTypes = List(new FilterType1, new FilterType2)
def returnChallenge(level: String, size: String): Challenge = {
val mediumLevel = level == "medium"
val r = new scala.util.Random
val alphabet = "abcdefghijklmnopqrstuvwxyz"
val n = 8
val secret = LazyList.continually(r.nextInt(alphabet.size)).map(alphabet).take(n).mkString
val canvas = new BufferedImage(225, 50, BufferedImage.TYPE_INT_RGB)
val characters = if (mediumLevel) HelperFunctions.safeAlphaNum else HelperFunctions.safeCharacters
val n = if (mediumLevel) 5 else 7
val secret = LazyList.continually(r.nextInt(characters.size)).map(characters).take(n).mkString
val size2D = HelperFunctions.parseSize2D(size)
val width = size2D(0)
val height = size2D(1)
val canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
val g = canvas.createGraphics()
val fontHeight = (height * 0.6).toInt
g.setColor(Color.WHITE)
g.fillRect(0, 0, canvas.getWidth, canvas.getHeight)
g.setColor(Color.BLACK)
g.setFont(new Font("Serif", Font.PLAIN, 30))
g.drawString(secret, 5, 30)
val font = new Font("Serif", Font.BOLD, fontHeight)
g.setFont(font)
val stringWidth = g.getFontMetrics().stringWidth(secret)
val scaleX = if (stringWidth > width) width / (stringWidth.toDouble) else 1d
val margin = if (stringWidth > width) 0 else (width - stringWidth)
val xOffset = (margin * r.nextDouble).toInt
g.scale(scaleX, 1d)
g.drawString(secret, xOffset, fontHeight)
g.dispose()
var image = ImmutableImage.fromAwt(canvas)
val s = scala.util.Random.nextInt(2)
image = filterTypes(s).applyFilter(image)
new Challenge(image.bytes(new nio.PngWriter()), "image/png", secret)
val s = r.nextInt(2)
image = filterTypes(s).applyFilter(image, !mediumLevel)
val img = image.awt()
val baos = new ByteArrayOutputStream()
PngImageWriter.write(baos, img);
new Challenge(baos.toByteArray, "image/png", secret)
}
def checkAnswer(secret: String, answer: String): Boolean = {
secret == answer
@ -49,14 +70,15 @@ class FilterChallenge extends ChallengeProvider {
}
trait FilterType {
def applyFilter(image: ImmutableImage): ImmutableImage
def applyFilter(image: ImmutableImage, hardLevel: Boolean): ImmutableImage
}
class FilterType1 extends FilterType {
override def applyFilter(image: ImmutableImage): ImmutableImage = {
val blur = new GaussianBlurFilter(2)
override def applyFilter(image: ImmutableImage, hardLevel: Boolean): ImmutableImage = {
val radius = if (hardLevel) 3 else 2
val blur = new GaussianBlurFilter(radius)
val smear = new SmearFilter(com.sksamuel.scrimage.filter.SmearType.Circles, 10, 10, 10, 0, 1)
val diffuse = new DiffuseFilter(2)
val diffuse = new DiffuseFilter(radius.toFloat)
blur.apply(image)
diffuse.apply(image)
smear.apply(image)
@ -65,9 +87,10 @@ class FilterType1 extends FilterType {
}
class FilterType2 extends FilterType {
override def applyFilter(image: ImmutableImage): ImmutableImage = {
override def applyFilter(image: ImmutableImage, hardLevel: Boolean): ImmutableImage = {
val radius = if (hardLevel) 2f else 1f
val smear = new SmearFilter(com.sksamuel.scrimage.filter.SmearType.Circles, 10, 10, 10, 0, 1)
val diffuse = new DiffuseFilter(1)
val diffuse = new DiffuseFilter(radius)
val ripple = new RippleFilter(com.sksamuel.scrimage.filter.RippleType.Noise, 1, 1, 0.005.toFloat, 0.005.toFloat)
diffuse.apply(image)
ripple.apply(image)

View File

@ -10,6 +10,7 @@ import java.awt.Color
import lc.captchas.interfaces.ChallengeProvider
import lc.captchas.interfaces.Challenge
import java.util.{List => JavaList, Map => JavaMap}
import lc.misc.PngImageWriter
class LabelCaptcha extends ChallengeProvider {
private var knownFiles = new File("known").list.toList
@ -30,13 +31,16 @@ class LabelCaptcha extends ChallengeProvider {
def supportedParameters(): JavaMap[String, JavaList[String]] = {
JavaMap.of(
"supportedLevels", JavaList.of("hard"),
"supportedMedia", JavaList.of("image/png"),
"supportedInputType", JavaList.of("text")
"supportedLevels",
JavaList.of("hard"),
"supportedMedia",
JavaList.of("image/png"),
"supportedInputType",
JavaList.of("text")
)
}
def returnChallenge(): Challenge =
def returnChallenge(level: String, size: String): Challenge =
synchronized {
val r = scala.util.Random.nextInt(knownFiles.length)
val s = scala.util.Random.nextInt(unknownFiles.length)
@ -49,7 +53,7 @@ class LabelCaptcha extends ChallengeProvider {
val token = encrypt(knownImageFile + "," + unknownImageFile)
val baos = new ByteArrayOutputStream()
ImageIO.write(mergedImage, "png", baos)
PngImageWriter.write(baos, mergedImage);
new Challenge(baos.toByteArray(), "image/png", token)
}

View File

@ -11,6 +11,7 @@ import lc.captchas.interfaces.ChallengeProvider
import lc.captchas.interfaces.Challenge
import lc.misc.GifSequenceWriter
import java.util.{List => JavaList, Map => JavaMap}
import lc.misc.HelperFunctions
class Drop {
var x = 0
@ -24,8 +25,6 @@ class Drop {
}
class RainDropsCP extends ChallengeProvider {
private val alphabet = "abcdefghijklmnopqrstuvwxyz"
private val n = 6
private val bgColor = new Color(200, 200, 200)
private val textColor = new Color(208, 208, 218)
private val textHighlightColor = new Color(100, 100, 125)
@ -38,9 +37,12 @@ class RainDropsCP extends ChallengeProvider {
def supportedParameters(): JavaMap[String, JavaList[String]] = {
JavaMap.of(
"supportedLevels", JavaList.of("medium", "easy"),
"supportedMedia", JavaList.of("image/gif"),
"supportedInputType", JavaList.of("text")
"supportedLevels",
JavaList.of("medium", "easy"),
"supportedMedia",
JavaList.of("image/gif"),
"supportedInputType",
JavaList.of("text")
)
}
@ -53,11 +55,13 @@ class RainDropsCP extends ChallengeProvider {
})
}
def returnChallenge(): Challenge = {
def returnChallenge(level: String, size: String): Challenge = {
val r = new scala.util.Random
val secret = LazyList.continually(r.nextInt(alphabet.size)).map(alphabet).take(n).mkString
val width = 450
val height = 100
val n = if (level == "easy") 4 else 6
val secret = HelperFunctions.randomString(n, HelperFunctions.safeAlphaNum)
val size2D = HelperFunctions.parseSize2D(size)
val width = size2D(0)
val height = size2D(1)
val imgType = BufferedImage.TYPE_INT_RGB
val xOffset = 2 + r.nextInt(3)
val xBias = (height / 10) - 2
@ -77,7 +81,8 @@ class RainDropsCP extends ChallengeProvider {
xOffset
)
val baseFont = new Font(Font.MONOSPACED, Font.BOLD, 80)
val fontHeight = (height * 0.5f).toInt
val baseFont = new Font(Font.MONOSPACED, Font.BOLD, fontHeight)
val attributes = new java.util.HashMap[TextAttribute, Object]()
attributes.put(TextAttribute.TRACKING, Double.box(0.2))
attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_EXTRABOLD)
@ -114,17 +119,22 @@ class RainDropsCP extends ChallengeProvider {
}
}
// center the text
g.setFont(spacedFont)
val textWidth = g.getFontMetrics().charsWidth(secret.toCharArray, 0, secret.toCharArray.length)
val textX = (width - textWidth) / 2
val textWidth = g.getFontMetrics().stringWidth(secret)
val scaleX = if (textWidth > width) width / textWidth.toDouble else 1.0d
g.scale(scaleX, 1)
// paint the top outline
// center the text
val textX = if (textWidth > width) 0 else ((width - textWidth) / 2)
// this will be overlapped by the following text to show the top outline because of the offset
val yOffset = (fontHeight * 0.01).ceil.toInt
g.setColor(textHighlightColor)
g.drawString(secret, textX, 69)
g.drawString(secret, textX, (fontHeight * 1.1).toInt - yOffset)
// paint the text
g.setColor(textColor)
g.drawString(secret, textX, 70)
g.drawString(secret, textX, (fontHeight * 1.1).toInt)
g.dispose()
writer.writeToSequence(canvas)

View File

@ -10,7 +10,7 @@ object ParametersEnum extends Enumeration {
val ALLOWEDLEVELS: Value = Value("allowedLevels")
val ALLOWEDMEDIA: Value = Value("allowedMedia")
val ALLOWEDINPUTTYPE: Value = Value("allowedInputType")
val ALLOWEDSIZES: Value = Value("allowedSizes")
}
object AttributesEnum extends Enumeration {
@ -19,10 +19,14 @@ object AttributesEnum extends Enumeration {
val NAME: Value = Value("name")
val RANDOM_SEED: Value = Value("randomSeed")
val PORT: Value = Value("port")
val ADDRESS: Value = Value("address")
val CAPTCHA_EXPIRY_TIME_LIMIT: Value = Value("captchaExpiryTimeLimit")
val THROTTLE: Value = Value("throttle")
val BUFFER_COUNT: Value = Value("bufferCount")
val THREAD_DELAY: Value = Value("threadDelay")
val PLAYGROUND_ENABLED: Value = Value("playgroundEnabled")
val CORS_HEADER: Value = Value("corsHeader")
val CONFIG: Value = Value("config")
val MAX_ATTEMPTS_RATIO: Value = Value("maxAttemptsRatio")
}
object ResultEnum extends Enumeration {

View File

@ -1,15 +1,12 @@
package lc.core
import java.sql.ResultSet
import java.util.UUID
import java.io.ByteArrayInputStream
import lc.captchas.interfaces.{Challenge, ChallengeProvider}
import lc.database.Statements
import lc.core.CaptchaProviders
import lc.captchas.interfaces.ChallengeProvider
import lc.captchas.interfaces.Challenge
import java.sql.Blob
import java.io.ByteArrayInputStream
import java.sql.{Blob, ResultSet}
import java.util.UUID
object Captcha {
class CaptchaManager(config: Config, captchaProviders: CaptchaProviders) {
def getCaptcha(id: Id): Either[Error, Image] = {
val blob = getImage(id.id)
@ -37,17 +34,19 @@ object Captcha {
}
def generateChallenge(param: Parameters): Option[Int] = {
val provider = CaptchaProviders.getProvider(param)
provider match {
case Some(value) => {
val providerId = value.getId()
val challenge = value.returnChallenge()
try {
captchaProviders.getProvider(param).flatMap { provider =>
val providerId = provider.getId()
val challenge = provider.returnChallenge(param.level, param.size)
val blob = new ByteArrayInputStream(challenge.content)
val token = insertCaptcha(value, challenge, providerId, param, blob)
val token = insertCaptcha(provider, challenge, providerId, param, blob)
// println("Added new challenge: " + token.toString)
token.map(_.toInt)
}
case None => None
} catch {
case e: Exception =>
e.printStackTrace()
None
}
}
@ -65,7 +64,8 @@ object Captcha {
insertPstmt.setString(4, challenge.contentType)
insertPstmt.setString(5, param.level)
insertPstmt.setString(6, param.input_type)
insertPstmt.setBlob(7, blob)
insertPstmt.setString(7, param.size)
insertPstmt.setBlob(8, blob)
insertPstmt.executeUpdate()
val rs: ResultSet = insertPstmt.getGeneratedKeys()
if (rs.next()) {
@ -75,9 +75,9 @@ object Captcha {
}
}
val allowedInputType = Config.allowedInputType
val allowedLevels = Config.allowedLevels
val allowedMedia = Config.allowedMedia
val allowedInputType = config.allowedInputType
val allowedLevels = config.allowedLevels
val allowedMedia = config.allowedMedia
private def validateParam(param: Parameters): Array[String] = {
var invalid_params = Array[String]()
@ -108,11 +108,31 @@ object Captcha {
}
}
def getCount(param: Parameters): Option[Int] = {
val countPstmt = Statements.tlStmts.get.countForParameterPstmt
countPstmt.setString(1, param.level)
countPstmt.setString(2, param.media)
countPstmt.setString(3, param.input_type)
countPstmt.setString(4, param.size.toString())
val rs = countPstmt.executeQuery()
if (rs.next()) {
Some(rs.getInt("count"))
} else {
None
}
}
private def getToken(param: Parameters): Option[Int] = {
val count = getCount(param).getOrElse(0)
if (count == 0) {
None
} else {
val tokenPstmt = Statements.tlStmts.get.tokenPstmt
tokenPstmt.setString(1, param.level)
tokenPstmt.setString(2, param.media)
tokenPstmt.setString(3, param.input_type)
tokenPstmt.setString(4, param.size)
tokenPstmt.setInt(5, count)
val rs = tokenPstmt.executeQuery()
if (rs.next()) {
Some(rs.getInt("token"))
@ -120,6 +140,7 @@ object Captcha {
None
}
}
}
private def updateAttempted(token: Int): Unit = {
val updateAttemptedPstmt = Statements.tlStmts.get.updateAttemptedPstmt
@ -142,7 +163,7 @@ object Captcha {
case None => Right(Success(ResultEnum.EXPIRED.toString))
case Some(value) => {
val (provider, secret) = value
val check = CaptchaProviders.getProviderById(provider).checkAnswer(secret, answer.answer)
val check = captchaProviders.getProviderById(provider).checkAnswer(secret, answer.answer)
deleteCaptcha(answer.id)
val result = if (check) ResultEnum.TRUE.toString else ResultEnum.FALSE.toString
Right(Success(result))
@ -152,7 +173,7 @@ object Captcha {
private def getSecret(id: String): Option[(String, String)] = {
val selectPstmt = Statements.tlStmts.get.selectPstmt
selectPstmt.setInt(1, Config.captchaExpiryTimeLimit)
selectPstmt.setInt(1, config.captchaExpiryTimeLimit)
selectPstmt.setString(2, id)
val rs: ResultSet = selectPstmt.executeQuery()
if (rs.first()) {

View File

@ -1,12 +1,12 @@
package lc.core
import lc.captchas._
import lc.captchas.*
import lc.captchas.interfaces.ChallengeProvider
import lc.captchas.interfaces.Challenge
import scala.collection.mutable.Map
import lc.misc.HelperFunctions
object CaptchaProviders {
class CaptchaProviders(config: Config) {
private val providers = Map(
"FilterChallenge" -> new FilterChallenge,
// "FontFunCaptcha" -> new FontFunCaptcha,
@ -18,13 +18,12 @@ object CaptchaProviders {
)
def generateChallengeSamples(): Map[String, Challenge] = {
providers.map {
case (key, provider) =>
(key, provider.returnChallenge())
providers.map { case (key, provider) =>
(key, provider.returnChallenge("easy", "350x100"))
}
}
private val config = Config.captchaConfig
private val captchaConfig = config.captchaConfig
def getProviderById(id: String): ChallengeProvider = {
return providers(id)
@ -32,10 +31,11 @@ object CaptchaProviders {
private def filterProviderByParam(param: Parameters): Iterable[(String, String)] = {
val configFilter = for {
configValue <- config
configValue <- captchaConfig
if configValue.allowedLevels.contains(param.level)
if configValue.allowedMedia.contains(param.media)
if configValue.allowedInputType.contains(param.input_type)
if configValue.allowedSizes.contains(param.size)
} yield (configValue.name, configValue.config)
val providerFilter = for {
@ -51,7 +51,7 @@ object CaptchaProviders {
def getProvider(param: Parameters): Option[ChallengeProvider] = {
val providerConfig = filterProviderByParam(param).toList
if (providerConfig.length > 0) {
if (providerConfig.nonEmpty) {
val randomIndex = HelperFunctions.randomNumber(providerConfig.length)
val providerIndex = providerConfig(randomIndex)._1
val selectedProvider = providers(providerIndex)

View File

@ -4,15 +4,17 @@ import scala.io.Source.fromFile
import org.json4s.{DefaultFormats, JValue, JObject, JField, JString}
import org.json4s.jackson.JsonMethods.{parse, render, pretty}
import org.json4s.JsonDSL._
import org.json4s.StringInput
import org.json4s.jvalue2monadic
import org.json4s.jvalue2extractable
import java.io.{FileNotFoundException, File, PrintWriter}
import java.{util => ju}
import lc.misc.HelperFunctions
object Config {
class Config(configFilePath: String) {
implicit val formats: DefaultFormats.type = DefaultFormats
import Config.formats
private val configFilePath = "data/config.json"
private val configString =
try {
val configFile = fromFile(configFilePath)
@ -22,7 +24,12 @@ object Config {
} catch {
case _: FileNotFoundException => {
val configFileContent = getDefaultConfig()
val configFile = new PrintWriter(new File(configFilePath))
val file = if (new File(configFilePath).isDirectory) {
new File(configFilePath.concat("/config.json"))
} else {
new File(configFilePath)
}
val configFile = new PrintWriter(file)
configFile.write(configFileContent)
configFile.close
configFileContent
@ -34,16 +41,21 @@ object Config {
}
private val configJson = parse(configString)
private val configFields: ConfigField = configJson.extract[ConfigField]
val port: Int = (configJson \ AttributesEnum.PORT.toString).extract[Int]
val throttle: Int = (configJson \ AttributesEnum.THROTTLE.toString).extract[Int]
val seed: Int = (configJson \ AttributesEnum.RANDOM_SEED.toString).extract[Int]
val captchaExpiryTimeLimit: Int = (configJson \ AttributesEnum.CAPTCHA_EXPIRY_TIME_LIMIT.toString).extract[Int]
val threadDelay: Int = (configJson \ AttributesEnum.THREAD_DELAY.toString).extract[Int]
val port: Int = configFields.portInt.getOrElse(8888)
val address: String = configFields.address.getOrElse("0.0.0.0")
val bufferCount: Int = configFields.bufferCountInt.getOrElse(1000)
val seed: Int = configFields.seedInt.getOrElse(375264328)
val captchaExpiryTimeLimit: Int = configFields.captchaExpiryTimeLimitInt.getOrElse(5)
val threadDelay: Int = configFields.threadDelayInt.getOrElse(2)
val playgroundEnabled: Boolean = configFields.playgroundEnabledBool.getOrElse(true)
val corsHeader: String = configFields.corsHeader.getOrElse("")
val maxAttempts: Int = Math.max(1, (configFields.maxAttemptsRatioFloat.getOrElse(0.01f) * bufferCount).toInt)
private val captchaConfigJson = (configJson \ "captchas")
val captchaConfigTransform: JValue = captchaConfigJson transformField {
case JField("config", JObject(config)) => ("config", JString(config.toString))
val captchaConfigTransform: JValue = captchaConfigJson transformField { case JField("config", JObject(config)) =>
("config", JString(config.toString))
}
val captchaConfig: List[CaptchaConfig] = captchaConfigTransform.extract[List[CaptchaConfig]]
val allowedLevels: Set[String] = captchaConfig.flatMap(_.allowedLevels).toSet
@ -56,15 +68,20 @@ object Config {
val defaultConfigMap =
(AttributesEnum.RANDOM_SEED.toString -> new ju.Random().nextInt()) ~
(AttributesEnum.PORT.toString -> 8888) ~
(AttributesEnum.ADDRESS.toString -> "0.0.0.0") ~
(AttributesEnum.CAPTCHA_EXPIRY_TIME_LIMIT.toString -> 5) ~
(AttributesEnum.THROTTLE.toString -> 1000) ~
(AttributesEnum.BUFFER_COUNT.toString -> 1000) ~
(AttributesEnum.THREAD_DELAY.toString -> 2) ~
(AttributesEnum.PLAYGROUND_ENABLED.toString -> true) ~
(AttributesEnum.CORS_HEADER.toString -> "") ~
(AttributesEnum.MAX_ATTEMPTS_RATIO.toString -> 0.01f) ~
("captchas" -> List(
(
(AttributesEnum.NAME.toString -> "FilterChallenge") ~
(ParametersEnum.ALLOWEDLEVELS.toString -> List("medium", "hard")) ~
(ParametersEnum.ALLOWEDMEDIA.toString -> List("image/png")) ~
(ParametersEnum.ALLOWEDINPUTTYPE.toString -> List("text")) ~
(ParametersEnum.ALLOWEDSIZES.toString -> List("350x100")) ~
(AttributesEnum.CONFIG.toString -> JObject())
),
(
@ -72,6 +89,7 @@ object Config {
(ParametersEnum.ALLOWEDLEVELS.toString -> List("hard")) ~
(ParametersEnum.ALLOWEDMEDIA.toString -> List("image/gif")) ~
(ParametersEnum.ALLOWEDINPUTTYPE.toString -> List("text")) ~
(ParametersEnum.ALLOWEDSIZES.toString -> List("350x100")) ~
(AttributesEnum.CONFIG.toString -> JObject())
),
(
@ -79,6 +97,7 @@ object Config {
(ParametersEnum.ALLOWEDLEVELS.toString -> List("easy")) ~
(ParametersEnum.ALLOWEDMEDIA.toString -> List("image/png")) ~
(ParametersEnum.ALLOWEDINPUTTYPE.toString -> List("text")) ~
(ParametersEnum.ALLOWEDSIZES.toString -> List("350x100")) ~
(AttributesEnum.CONFIG.toString -> JObject())
),
(
@ -86,6 +105,7 @@ object Config {
(ParametersEnum.ALLOWEDLEVELS.toString -> List("easy", "medium")) ~
(ParametersEnum.ALLOWEDMEDIA.toString -> List("image/gif")) ~
(ParametersEnum.ALLOWEDINPUTTYPE.toString -> List("text")) ~
(ParametersEnum.ALLOWEDSIZES.toString -> List("350x100")) ~
(AttributesEnum.CONFIG.toString -> JObject())
)
))
@ -94,3 +114,7 @@ object Config {
}
}
object Config {
implicit val formats: DefaultFormats.type = DefaultFormats
}

View File

@ -5,7 +5,7 @@ import lc.core.Config.formats
trait ByteConvert { def toBytes(): Array[Byte] }
case class Size(height: Int, width: Int)
case class Parameters(level: String, media: String, input_type: String, size: Option[Size])
case class Parameters(level: String, media: String, input_type: String, size: String)
case class Id(id: String) extends ByteConvert { def toBytes(): Array[Byte] = { write(this).getBytes } }
case class Image(image: Array[Byte]) extends ByteConvert { def toBytes(): Array[Byte] = { image } }
case class Answer(answer: String, id: String)
@ -16,5 +16,32 @@ case class CaptchaConfig(
allowedLevels: List[String],
allowedMedia: List[String],
allowedInputType: List[String],
allowedSizes: List[String],
config: String
)
case class ConfigField(
port: Option[Integer],
address: Option[String],
bufferCount: Option[Integer],
seed: Option[Integer],
captchaExpiryTimeLimit: Option[Integer],
threadDelay: Option[Integer],
playgroundEnabled: Option[java.lang.Boolean],
corsHeader: Option[String],
maxAttemptsRatio: Option[java.lang.Float]
) {
lazy val portInt: Option[Int] = mapInt(port)
lazy val bufferCountInt: Option[Int] = mapInt(bufferCount)
lazy val seedInt: Option[Int] = mapInt(seed)
lazy val captchaExpiryTimeLimitInt: Option[Int] = mapInt(captchaExpiryTimeLimit)
lazy val threadDelayInt: Option[Int] = mapInt(threadDelay)
lazy val maxAttemptsRatioFloat: Option[Float] = mapFloat(maxAttemptsRatio)
lazy val playgroundEnabledBool: Option[Boolean] = playgroundEnabled.map(_ || false)
private def mapInt(x: Option[Integer]): Option[Int] = {
x.map(_ + 0)
}
private def mapFloat(x: Option[java.lang.Float]): Option[Float] = {
x.map(_ + 0.0f)
}
}

View File

@ -1,9 +1,10 @@
package lc.database
import java.sql._
import java.sql.{Connection, DriverManager, Statement}
class DBConn() {
val con: Connection = DriverManager.getConnection("jdbc:h2:./data/H2/captcha", "sa", "")
val con: Connection =
DriverManager.getConnection("jdbc:h2:./data/H2/captcha3;MAX_COMPACT_TIME=8000;DB_CLOSE_ON_EXIT=FALSE", "sa", "")
def getStatement(): Statement = {
con.createStatement()

View File

@ -17,6 +17,7 @@ class Statements(dbConn: DBConn, maxAttempts: Int) {
"contentType varchar, " +
"contentLevel varchar, " +
"contentInput varchar, " +
"size varchar, " +
"image blob, " +
"attempted int default 0, " +
"PRIMARY KEY(token));" +
@ -37,8 +38,8 @@ class Statements(dbConn: DBConn, maxAttempts: Int) {
val insertPstmt: PreparedStatement = dbConn.con.prepareStatement(
"INSERT INTO " +
"challenge(id, secret, provider, contentType, contentLevel, contentInput, image) " +
"VALUES (?, ?, ?, ?, ?, ?, ?)",
"challenge(id, secret, provider, contentType, contentLevel, contentInput, size, image) " +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
Statement.RETURN_GENERATED_KEYS
)
@ -70,6 +71,18 @@ class Statements(dbConn: DBConn, maxAttempts: Int) {
"WHERE token = ?;"
)
val countForParameterPstmt: PreparedStatement = dbConn.con.prepareStatement(
s"""
SELECT count(*) as count
FROM challenge
WHERE attempted < $maxAttempts AND
contentLevel = ? AND
contentType = ? AND
contentInput = ? AND
size = ?
"""
)
val tokenPstmt: PreparedStatement = dbConn.con.prepareStatement(
s"""
SELECT token, attempted
@ -77,8 +90,11 @@ class Statements(dbConn: DBConn, maxAttempts: Int) {
WHERE attempted < $maxAttempts AND
contentLevel = ? AND
contentType = ? AND
contentInput = ?
ORDER BY attempted ASC LIMIT 1"""
contentInput = ? AND
size = ?
LIMIT 1
OFFSET FLOOR(RAND()*?)
"""
)
val deleteAnswerPstmt: PreparedStatement = dbConn.con.prepareStatement(
@ -107,6 +123,14 @@ class Statements(dbConn: DBConn, maxAttempts: Int) {
"SELECT * FROM mapId"
)
val shutdown: PreparedStatement = dbConn.con.prepareStatement(
"SHUTDOWN"
)
val shutdownCompact: PreparedStatement = dbConn.con.prepareStatement(
"SHUTDOWN COMPACT"
)
}
object Statements {
@ -118,6 +142,6 @@ object Statements {
```
*/
private val dbConn: DBConn = new DBConn()
private val maxAttempts = 10
var maxAttempts: Int = 10
val tlStmts: ThreadLocal[Statements] = ThreadLocal.withInitial(() => new Statements(dbConn, maxAttempts))
}

View File

@ -1,53 +1,67 @@
package lc.server
import org.json4s.jackson.JsonMethods.parse
import lc.core.Captcha
import org.json4s.jvalue2extractable
import lc.core.CaptchaManager
import lc.core.ErrorMessageEnum
import lc.core.{Parameters, Id, Answer, Error, ByteConvert}
import lc.core.{Answer, ByteConvert, Error, Id, Parameters}
import lc.core.Config.formats
import org.limium.picoserve
import org.limium.picoserve.Server.ByteResponse
import org.limium.picoserve.Server.{ByteResponse, ServerBuilder, StringResponse}
import scala.io.Source
import org.limium.picoserve.Server.StringResponse
import java.net.InetSocketAddress
import java.util
import scala.jdk.CollectionConverters._
class Server(port: Int) {
val server: picoserve.Server = picoserve.Server
class Server(
address: String,
port: Int,
captchaManager: CaptchaManager,
playgroundEnabled: Boolean,
corsHeader: String
) {
var headerMap: util.Map[String, util.List[String]] = _
if (corsHeader.nonEmpty) {
headerMap = Map("Access-Control-Allow-Origin" -> List(corsHeader).asJava).asJava
}
val serverBuilder: ServerBuilder = picoserve.Server
.builder()
.port(port)
.address(new InetSocketAddress(address, port))
.backlog(32)
.POST(
"/v1/captcha",
"/v2/captcha",
(request) => {
val json = parse(request.getBodyString())
val param = json.extract[Parameters]
val id = Captcha.getChallenge(param)
getResponse(id)
val id = captchaManager.getChallenge(param)
getResponse(id, headerMap)
}
)
.GET(
"/v1/media",
"/v2/media",
(request) => {
val params = request.getQueryParams()
val result = if (params.containsKey("id")) {
val paramId = params.get("id").get(0)
val id = Id(paramId)
Captcha.getCaptcha(id)
captchaManager.getCaptcha(id)
} else {
Left(Error(ErrorMessageEnum.INVALID_PARAM.toString + "=> id"))
}
getResponse(result)
getResponse(result, headerMap)
}
)
.POST(
"/v1/answer",
"/v2/answer",
(request) => {
val json = parse(request.getBodyString())
val answer = json.extract[Answer]
val result = Captcha.checkAnswer(answer)
getResponse(result)
val result = captchaManager.checkAnswer(answer)
getResponse(result, headerMap)
}
)
.GET(
if (playgroundEnabled) {
serverBuilder.GET(
"/demo/index.html",
(_) => {
val resStream = getClass().getResourceAsStream("/index.html")
@ -55,21 +69,40 @@ class Server(port: Int) {
new StringResponse(200, str)
}
)
.build()
serverBuilder.GET(
"/",
(_) => {
val str = """
<html>
<h2>Welcome to LibreCaptcha server</h2>
<h3><a href="/demo/index.html">Link to Demo</a></h3>
<h3>API is served at <b>/v2/</b></h3>
</html>
"""
new StringResponse(200, str)
}
)
println("Playground enabled on /demo/index.html")
}
private def getResponse(response: Either[Error, ByteConvert]): ByteResponse = {
val server: picoserve.Server = serverBuilder.build()
private def getResponse(
response: Either[Error, ByteConvert],
responseHeaders: util.Map[String, util.List[String]]
): ByteResponse = {
response match {
case Right(value) => {
new ByteResponse(200, value.toBytes())
new ByteResponse(200, value.toBytes(), responseHeaders)
}
case Left(value) => {
new ByteResponse(500, value.toBytes())
new ByteResponse(500, value.toBytes(), responseHeaders)
}
}
}
def start(): Unit = {
println("Starting server on port:" + port)
println("Starting server on " + address + ":" + port)
server.start()
}
}

View File

@ -1,14 +1,19 @@
{
"randomSeed" : 20,
"port" : 8888,
"address" : "0.0.0.0",
"captchaExpiryTimeLimit" : 5,
"throttle" : 10,
"bufferCount" : 10,
"threadDelay" : 2,
"playgroundEnabled" : false,
"corsHeader" : "*",
"maxAttemptsRatio" : 0.01,
"captchas" : [ {
"name" : "DebugCaptcha",
"allowedLevels" : [ "debug" ],
"allowedMedia" : [ "image/png" ],
"allowedInputType" : [ "text" ],
"allowedSizes" : [ "350x100" ],
"config" : { }
}]
}

View File

@ -22,9 +22,9 @@ class QuickStartUser(SequentialTaskSet):
@task
def captcha(self):
captcha_params = {"level":"debug","media":"image/png","input_type":"text"}
captcha_params = {"level":"debug","media":"image/png","input_type":"text", "size":"350x100"}
with self.client.post(path="/v1/captcha", json=captcha_params, name="/captcha", catch_response = True) as resp:
with self.client.post(path="/v2/captcha", json=captcha_params, name="/captcha", catch_response = True) as resp:
if resp.status_code != 200:
resp.failure("Status was not 200: " + resp.text)
captchaJson = resp.json()
@ -32,7 +32,7 @@ class QuickStartUser(SequentialTaskSet):
if not uuid:
resp.failure("uuid not returned on /captcha endpoint: " + resp.text)
with self.client.get(path="/v1/media?id=%s" % uuid, name="/media", stream=True, catch_response = True) as resp:
with self.client.get(path="/v2/media?id=%s" % uuid, name="/media", stream=True, catch_response = True) as resp:
if resp.status_code != 200:
resp.failure("Status was not 200: " + resp.text)
@ -41,7 +41,7 @@ class QuickStartUser(SequentialTaskSet):
ocrAnswer = self.solve(uuid, media)
answerBody = {"answer": ocrAnswer,"id": uuid}
with self.client.post(path='/v1/answer', json=answerBody, name="/answer", catch_response=True) as resp:
with self.client.post(path='/v2/answer', json=answerBody, name="/answer", catch_response=True) as resp:
if resp.status_code != 200:
resp.failure("Status was not 200: " + resp.text)
else:

View File

@ -24,9 +24,9 @@ class QuickStartUser(SequentialTaskSet):
@task
def captcha(self):
# TODO: Iterate over parameters for a more comprehensive test
captcha_params = {"level":"easy","media":"image/png","input_type":"text"}
captcha_params = {"level":"easy","media":"image/png","input_type":"text", "size":"350x100"}
resp = self.client.post(path="/v1/captcha", json=captcha_params, name="/captcha")
resp = self.client.post(path="/v2/captcha", json=captcha_params, name="/captcha")
if resp.status_code != 200:
print("\nError on /captcha endpoint: ")
print(resp)
@ -36,14 +36,14 @@ class QuickStartUser(SequentialTaskSet):
uuid = json.loads(resp.text).get("id")
answerBody = {"answer": "qwer123","id": uuid}
resp = self.client.get(path="/v1/media?id=%s" % uuid, name="/media")
resp = self.client.get(path="/v2/media?id=%s" % uuid, name="/media")
if resp.status_code != 200:
print("\nError on /media endpoint: ")
print(resp)
print(resp.text)
print("----------------END.MEDIA-------------------\n\n")
resp = self.client.post(path='/v1/answer', json=answerBody, name="/answer")
resp = self.client.post(path='/v2/answer', json=answerBody, name="/answer")
if resp.status_code != 200:
print("\nError on /answer endpoint: ")
print(resp)

View File

@ -4,7 +4,7 @@ python3 -m venv testEnv
source ./testEnv/bin/activate
pip install locust
mkdir -p data/
java -jar target/scala-2.13/LibreCaptcha.jar &
java -jar target/scala-3.6.2/LibreCaptcha.jar &
JAVA_PID=$!
sleep 4
@ -22,7 +22,7 @@ echo Run functional test
cp data/config.json data/config.json.bak
cp tests/debug-config.json data/config.json
java -jar target/scala-2.13/LibreCaptcha.jar &
java -jar target/scala-3.6.2/LibreCaptcha.jar &
JAVA_PID=$!
sleep 4