Skip to content
This repository has been archived by the owner on Jan 22, 2024. It is now read-only.

Commit

Permalink
Implement REFRESH_TOKEN based Pixiv Auth
Browse files Browse the repository at this point in the history
  • Loading branch information
SlashNephy committed Feb 27, 2021
1 parent 71b7902 commit 37a4fc7
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 47 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ services:
TWITTER_CS: xxx
TWITTER_AT: xxx
TWITTER_ATS: xxx
PIXIV_EMAIL: xxx
PIXIV_PASSWORD: xxx
PIXIV_REFRESH_TOKEN: xxx
NIJIE_EMAIL: xxx
NIJIE_PASSWORD: xxx

Expand Down
3 changes: 1 addition & 2 deletions src/jvmMain/kotlin/blue/starry/stella/Env.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ object Env {
val TWITTER_CS by stringOrNull
val TWITTER_AT by stringOrNull
val TWITTER_ATS by stringOrNull
val PIXIV_EMAIL by stringOrNull
val PIXIV_PASSWORD by stringOrNull
val PIXIV_REFRESH_TOKEN by stringOrNull
val NIJIE_EMAIL by stringOrNull
val NIJIE_PASSWORD by stringOrNull
}
Expand Down
9 changes: 3 additions & 6 deletions src/jvmMain/kotlin/blue/starry/stella/worker/Client.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ val StellaHttpClient by lazy {
install(HttpCookies)

Logging {
level = LogLevel.INFO
level = LogLevel.ALL
logger = object : Logger {
private val logger = KotlinLogging.logger("stella.http")

Expand All @@ -36,12 +36,9 @@ val StellaHttpClient by lazy {
}

val StellaPixivClient by lazy {
val (email, password) = Env.PIXIV_EMAIL to Env.PIXIV_PASSWORD
if (email == null || password == null) {
return@lazy null
}
val token = Env.PIXIV_REFRESH_TOKEN ?: return@lazy null

PixivClient(email, password)
PixivClient(token)
}

val StellaTwitterClient by lazy {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,56 +10,49 @@ import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import java.io.File
import java.security.MessageDigest
import java.time.Instant
import java.time.OffsetDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.*

class PixivClient(private val email: String, private val password: String) {
private val lock = Mutex()
class PixivClient(private val refreshToken: String) {
private val mutex = Mutex()

private var token: PixivModel.Token? = null
private val isLoggedIn: Boolean
get() = token != null

private val dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ", Locale.ENGLISH)
private fun HttpRequestBuilder.setHeaders(credentials: Boolean) {
DateTimeFormatter.ISO_DATE_TIME
val time = dateFormat.format(Instant.now())

userAgent("PixivAndroidApp/5.0.64 (Android 6.0)")
header("X-Client-Time", time)
header("X-Client-Hash", MessageDigest.getInstance("MD5").digest(
(time + "28c1fdd170a5204386cb1313c7077b34f83e4aaf4aa829ce78c231e05b0bae2c").toByteArray()
).joinToString("") {
"%02x".format(it)
})

if (credentials) {
requireNotNull(token)
header(HttpHeaders.Authorization, "Bearer ${token?.response?.accessToken}")
private suspend fun isLoggedIn(): Boolean {
return mutex.withLock {
token != null
}
}

private suspend fun login() {
if (isLoggedIn) {
if (isLoggedIn()) {
return
}

val parameters = Parameters.build {
append("grant_type", "password")
append("client_id", "MOBrBDS8blbauoSck0ZfDbtuzpyT")
append("username", email)
append("get_secure_url", "1")
append("password", password)
append("client_id", "MOBrBDS8blbauoSck0ZfDbtuzpyT")
append("client_secret", "lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj")
append("grant_type", "refresh_token")
append("refresh_token", refreshToken)
}

token = lock.withLock(token) {
token = mutex.withLock {
StellaHttpClient.submitForm<String>(parameters) {
url("https://oauth.secure.pixiv.net/auth/token")

setHeaders(false)
userAgent("PixivAndroidApp/5.0.234 (Android 11; Pixel 5)")
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssxxx")
val time = OffsetDateTime.now(ZoneId.of("UTC")).format(formatter)

header("X-Client-Time", time)
header("X-Client-Hash", MessageDigest.getInstance("MD5").digest(
(time + "28c1fdd170a5204386cb1313c7077b34f83e4aaf4aa829ce78c231e05b0bae2c").toByteArray()
).joinToString("") {
"%02x".format(it)
})
}.parseObject {
logger.trace { it }

PixivModel.Token(it)
}
}
Expand All @@ -68,7 +61,7 @@ class PixivClient(private val email: String, private val password: String) {
}

suspend fun logout() {
lock.withLock {
mutex.withLock {
token = null
}
}
Expand All @@ -80,7 +73,7 @@ class PixivClient(private val email: String, private val password: String) {
parameter("user_id", token?.response?.user?.id)
parameter("restrict", if (private) "private" else "public")

setHeaders(true)
setHeaders()
}.parseObject {
PixivModel.Bookmark(it)
}
Expand All @@ -94,8 +87,8 @@ class PixivClient(private val email: String, private val password: String) {
append("illust_id", id.toString())
}

return StellaHttpClient.submitForm("https://app-api.pixiv.net/v2/illust/bookmark/add", parameters) {
setHeaders(true)
StellaHttpClient.submitForm<Unit>("https://app-api.pixiv.net/v2/illust/bookmark/add", parameters) {
setHeaders()
}
}

Expand All @@ -106,8 +99,8 @@ class PixivClient(private val email: String, private val password: String) {
append("illust_id", id.toString())
}

return StellaHttpClient.submitForm("https://app-api.pixiv.net/v1/illust/bookmark/delete", parameters) {
setHeaders(true)
StellaHttpClient.submitForm<Unit>("https://app-api.pixiv.net/v1/illust/bookmark/delete", parameters) {
setHeaders()
}
}

Expand All @@ -119,5 +112,17 @@ class PixivClient(private val email: String, private val password: String) {

file.writeBytes(response)
}

private fun HttpRequestBuilder.setHeaders(requireAuth: Boolean = true) {
header("App-OS", "ios")
header("App-OS-Version", "12.2")
header("App-Version", "7.6.2")
userAgent("PixivIOSApp/7.6.2 (iOS 12.2; iPhone9,1)")

if (requireAuth) {
val token = token?.response?.accessToken ?: error("Login required.")
header(HttpHeaders.Authorization, "Bearer $token")
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ object PixivSourceProvider {
break
} catch (e: ResponseException) {
client.logout()
logger.error(e) { "PixivSource でγƒͺγ‚―γ‚¨γ‚Ήγƒˆγ«ε€±ζ•—γ—γΎγ—γŸγ€‚γƒ­γ‚°γ‚€γƒ³γ‚’θ©¦θ‘Œγ—γΎγ™γ€‚" }
} catch (e: Throwable) {
logger.error(e) { "PixivSource γ§δΎ‹ε€–γŒη™Ίη”Ÿγ—γΎγ—γŸγ€‚" }
}
Expand Down

0 comments on commit 37a4fc7

Please sign in to comment.