Merge branch 'no-libsodium' into 'master'

No libsodium

See merge request mangadex-pub/mangadex_at_home!65
This commit is contained in:
carbotaniuman 2020-08-22 03:23:18 +00:00
commit 602a43d62e
7 changed files with 3451 additions and 39 deletions

View file

@ -17,6 +17,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Security ### Security
## [1.2.2] - 2020-08-21
### Changed
- [2020-08-11] Moved to a Java implementation of NaCl [@carbotaniuman].
### Fixed
- [2020-08-11] Revert WebUI changes in 1.2.1 [@carbotaniuman].
## [1.2.1] - 2020-08-11 ## [1.2.1] - 2020-08-11
### Added ### Added
- [2020-08-11] New CLI for specifying database location, cache folder, and settings [@carbotaniuman]. - [2020-08-11] New CLI for specifying database location, cache folder, and settings [@carbotaniuman].
@ -234,7 +242,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- [2020-06-11] Tweaked logging configuration to reduce log file sizes by [@carbotaniuman]. - [2020-06-11] Tweaked logging configuration to reduce log file sizes by [@carbotaniuman].
[Unreleased]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/1.2.1...HEAD [Unreleased]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/1.2.2...HEAD
[1.2.1]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/1.2.1...1.2.2
[1.2.1]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/1.2.0...1.2.1 [1.2.1]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/1.2.0...1.2.1
[1.2.0]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/1.1.5...1.2.0 [1.2.0]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/1.1.5...1.2.0
[1.1.5]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/1.1.4...1.1.5 [1.1.5]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/1.1.4...1.1.5

View file

@ -1,7 +1,7 @@
FROM openjdk:15-alpine FROM openjdk:15-alpine
WORKDIR /mangahome WORKDIR /mangahome
COPY /build/libs/mangadex_at_home.jar . COPY /build/libs/mangadex_at_home.jar .
RUN apk update && apk add --no-cache libsodium RUN apk update
VOLUME "/mangahome/cache" VOLUME "/mangahome/cache"
EXPOSE 443 8080 EXPOSE 443 8080
CMD java -Dfile-level=off -Dstdout-level=trace -jar mangadex_at_home.jar CMD java -Dfile-level=off -Dstdout-level=trace -jar mangadex_at_home.jar

View file

@ -44,9 +44,6 @@ dependencies {
implementation group: "org.xerial", name: "sqlite-jdbc", version: "3.30.1" implementation group: "org.xerial", name: "sqlite-jdbc", version: "3.30.1"
implementation "com.goterl.lazycode:lazysodium-java:4.3.0"
implementation "net.java.dev.jna:jna:5.5.0"
implementation "info.picocli:picocli:4.5.0" implementation "info.picocli:picocli:4.5.0"
kapt "info.picocli:picocli-codegen:4.5.0" kapt "info.picocli:picocli-codegen:4.5.0"
} }

File diff suppressed because it is too large Load diff

View file

@ -21,7 +21,7 @@ package mdnet.base
import java.time.Duration import java.time.Duration
object Constants { object Constants {
const val CLIENT_BUILD = 18 const val CLIENT_BUILD = 19
@JvmField val MAX_AGE_CACHE: Duration = Duration.ofDays(14) @JvmField val MAX_AGE_CACHE: Duration = Duration.ofDays(14)

View file

@ -25,9 +25,6 @@ import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.readValue
import com.goterl.lazycode.lazysodium.LazySodiumJava
import com.goterl.lazycode.lazysodium.SodiumJava
import com.goterl.lazycode.lazysodium.exceptions.SodiumException
import java.io.BufferedInputStream import java.io.BufferedInputStream
import java.io.BufferedOutputStream import java.io.BufferedOutputStream
import java.io.File import java.io.File
@ -54,6 +51,7 @@ import mdnet.base.trace
import mdnet.base.warn import mdnet.base.warn
import mdnet.cache.CachingInputStream import mdnet.cache.CachingInputStream
import mdnet.cache.DiskLruCache import mdnet.cache.DiskLruCache
import mdnet.security.TweetNaclFast
import org.apache.http.client.config.CookieSpecs import org.apache.http.client.config.CookieSpecs
import org.apache.http.client.config.RequestConfig import org.apache.http.client.config.RequestConfig
import org.apache.http.impl.client.HttpClients import org.apache.http.impl.client.HttpClients
@ -91,6 +89,7 @@ class ImageServer(
private val executor = Executors.newCachedThreadPool() private val executor = Executors.newCachedThreadPool()
fun handler(dataSaver: Boolean, tokenized: Boolean = false): HttpHandler { fun handler(dataSaver: Boolean, tokenized: Boolean = false): HttpHandler {
val box = TweetNaclFast.SecretBox(remoteSettings.tokenKey)
return baseHandler().then { request -> return baseHandler().then { request ->
val chapterHash = Path.of("chapterHash")(request) val chapterHash = Path.of("chapterHash")(request)
val fileName = Path.of("fileName")(request) val fileName = Path.of("fileName")(request)
@ -114,19 +113,19 @@ class ImageServer(
} }
val token = try { val token = try {
JACKSON.readValue<Token>( JACKSON.readValue<Token>(
try { box.open(tokenArr.sliceArray(24 until tokenArr.size), tokenArr.sliceArray(0 until 24)).apply {
SODIUM.cryptoBoxOpenEasyAfterNm( if (this == null) {
tokenArr.sliceArray(24 until tokenArr.size), tokenArr.sliceArray(0 until 24), remoteSettings.tokenKey
)
} catch (_: SodiumException) {
LOGGER.info { "Request for $sanitizedUri rejected for invalid token" } LOGGER.info { "Request for $sanitizedUri rejected for invalid token" }
return@then Response(Status.FORBIDDEN) return@then Response(Status.FORBIDDEN)
} }
}
) )
} catch (e: JsonProcessingException) { } catch (e: JsonProcessingException) {
LOGGER.info { "Request for $sanitizedUri rejected for invalid token" } println(e)
LOGGER.info(e) { "Request for $sanitizedUri rejected for invalid token" }
return@then Response(Status.FORBIDDEN) return@then Response(Status.FORBIDDEN)
} }
println(token)
if (OffsetDateTime.now().isAfter(token.expires)) { if (OffsetDateTime.now().isAfter(token.expires)) {
LOGGER.info { "Request for $sanitizedUri rejected for expired token" } LOGGER.info { "Request for $sanitizedUri rejected for expired token" }
@ -164,6 +163,7 @@ class ImageServer(
snapshot.close() snapshot.close()
LOGGER.warn { "Removing broken cache file for $sanitizedUri" } LOGGER.warn { "Removing broken cache file for $sanitizedUri" }
cache.removeUnsafe(imageId.toCacheId()) cache.removeUnsafe(imageId.toCacheId())
cache.flush()
} }
request.handleCacheMiss(sanitizedUri, getRc4(rc4Bytes), imageId, imageDatum) request.handleCacheMiss(sanitizedUri, getRc4(rc4Bytes), imageId, imageDatum)
@ -276,8 +276,11 @@ class ImageServer(
if (editor.getLength(0) == contentLength.toLong()) { if (editor.getLength(0) == contentLength.toLong()) {
LOGGER.info { "Cache download for $sanitizedUri committed" } LOGGER.info { "Cache download for $sanitizedUri committed" }
editor.commit() editor.commit()
println("A")
cache.flush()
} else { } else {
LOGGER.warn { "Cache download for $sanitizedUri aborted" } LOGGER.warn { "Cache download for $sanitizedUri aborted" }
println("B")
editor.abort() editor.abort()
} }
} catch (e: Exception) { } catch (e: Exception) {
@ -317,7 +320,6 @@ class ImageServer(
.header("X-Cache", if (cached) "HIT" else "MISS") .header("X-Cache", if (cached) "HIT" else "MISS")
companion object { companion object {
private val SODIUM = LazySodiumJava(SodiumJava())
private val JACKSON: ObjectMapper = jacksonObjectMapper() private val JACKSON: ObjectMapper = jacksonObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.registerModule(JavaTimeModule()) .registerModule(JavaTimeModule())

View file

@ -19,31 +19,10 @@ along with this MangaDex@Home. If not, see <http://www.gnu.org/licenses/>.
/* ktlint-disable no-wildcard-imports */ /* ktlint-disable no-wildcard-imports */
package mdnet.base.server package mdnet.base.server
import com.goterl.lazycode.lazysodium.LazySodiumJava
import com.goterl.lazycode.lazysodium.exceptions.SodiumException
import com.goterl.lazycode.lazysodium.interfaces.Box
import java.security.MessageDigest import java.security.MessageDigest
import javax.crypto.Cipher import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec import javax.crypto.spec.SecretKeySpec
@Throws(SodiumException::class)
fun LazySodiumJava.cryptoBoxOpenEasyAfterNm(cipherBytes: ByteArray, nonce: ByteArray, sharedKey: ByteArray): String {
if (!Box.Checker.checkNonce(nonce.size)) {
throw SodiumException("Incorrect nonce length.")
}
if (!Box.Checker.checkBeforeNmBytes(sharedKey.size)) {
throw SodiumException("Incorrect shared secret key length.")
}
val message = ByteArray(cipherBytes.size - Box.MACBYTES)
val res: Boolean = cryptoBoxOpenEasyAfterNm(message, cipherBytes, cipherBytes.size.toLong(), nonce, sharedKey)
if (!res) {
throw SodiumException("Could not fully complete shared secret key decryption.")
}
return str(message)
}
fun getRc4(key: ByteArray): Cipher { fun getRc4(key: ByteArray): Cipher {
val rc4 = Cipher.getInstance("RC4") val rc4 = Cipher.getInstance("RC4")
rc4.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, "RC4")) rc4.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, "RC4"))