Skip to content

Commit

Permalink
Support social authentication (#230)
Browse files Browse the repository at this point in the history
  • Loading branch information
TAKESHI SHIMADA committed Jul 17, 2019
1 parent e1e9364 commit c5318cb
Show file tree
Hide file tree
Showing 54 changed files with 606 additions and 304 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import com.twitter.finagle.{OAuth2, Service, SimpleFilter}
import com.twitter.inject.Logging
import com.twitter.util.Future
import io.github.cactacea.backend.core.domain.repositories.AccountsRepository
import io.github.cactacea.backend.utils.auth.CactaceaContext
import io.github.cactacea.backend.utils.context.CactaceaContext

@Singleton
class OAuthFilter @Inject()(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package io.github.cactacea.backend.core.domain.repositories

import com.google.inject.{Inject, Singleton}
import com.twitter.util.Future
import io.github.cactacea.backend.core.domain.enums.{AccountStatusType, DeviceType}
import io.github.cactacea.backend.core.domain.enums.AccountStatusType
import io.github.cactacea.backend.core.domain.models.{Account, AccountStatus}
import io.github.cactacea.backend.core.infrastructure.dao.{AccountsDAO, DevicesDAO, PushNotificationSettingsDAO}
import io.github.cactacea.backend.core.infrastructure.dao.{AccountsDAO, AuthenticationsDAO, DevicesDAO, PushNotificationSettingsDAO}
import io.github.cactacea.backend.core.infrastructure.identifiers.{AccountId, MediumId, SessionId}
import io.github.cactacea.backend.core.infrastructure.models.Accounts
import io.github.cactacea.backend.core.infrastructure.validators.{AccountsValidator, MediumsValidator}
Expand All @@ -15,21 +15,30 @@ import io.github.cactacea.backend.core.util.responses.CactaceaErrors._
class AccountsRepository @Inject()(
accountsValidator: AccountsValidator,
mediumsValidator: MediumsValidator,
authenticationsDAO: AuthenticationsDAO,
accountsDAO: AccountsDAO,
devicesDAO: DevicesDAO,
notificationSettingsDAO: PushNotificationSettingsDAO

) {

def create(accountName: String,
udid: String,
deviceType: DeviceType,
userAgent: Option[String]): Future[Account] = {
def save(providerId: String, providerKey: String, accountName: String, displayName: Option[String]): Future[Account] = {
authenticationsDAO.find(providerId, providerKey).map(_.flatMap(_.accountId)).flatMap(_ match {
case Some(id) =>
accountsValidator.find(id.toSessionId)
case None =>
for {
i <- accountsDAO.create(accountName, displayName.getOrElse(accountName))
_ <- notificationSettingsDAO.create(i.toSessionId)
a <- accountsValidator.find(i.toSessionId)
} yield (a)
})
}

def create(accountName: String): Future[Account] = {
for {
_ <- accountsValidator.notExist(accountName)
i <- accountsDAO.create(accountName)
_ <- devicesDAO.create(udid, deviceType, userAgent, i.toSessionId)
_ <- notificationSettingsDAO.create(i.toSessionId)
a <- accountsValidator.find(i.toSessionId)
} yield (a)
Expand All @@ -42,13 +51,6 @@ class AccountsRepository @Inject()(
} yield (())
}

def find(accountName: String, udid: String, deviceType: DeviceType, userAgent: Option[String]): Future[Account] = {
for {
a <- accountsValidator.find(accountName)
_ <- devicesDAO.create(udid, deviceType, userAgent, a.id.toSessionId)
} yield (a)
}

def find(sessionId: SessionId): Future[Account] = {
accountsValidator.find(sessionId)
}
Expand Down Expand Up @@ -143,5 +145,9 @@ class AccountsRepository @Inject()(
})
}

def link(providerId: String, providerKey: String, accountId: AccountId): Future[Unit] = {
authenticationsDAO.link(providerId, providerKey, accountId)
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,25 @@ package io.github.cactacea.backend.core.domain.repositories

import com.google.inject.{Inject, Singleton}
import com.twitter.util.Future
import io.github.cactacea.backend.core.domain.enums.ActiveStatusType
import io.github.cactacea.backend.core.domain.enums.{ActiveStatusType, DeviceType}
import io.github.cactacea.backend.core.infrastructure.dao.DevicesDAO
import io.github.cactacea.backend.core.infrastructure.identifiers.SessionId
import io.github.cactacea.backend.core.infrastructure.identifiers.{AccountId, SessionId}
import io.github.cactacea.backend.core.infrastructure.validators.AuthenticationsValidator

@Singleton
class DevicesRepository @Inject()(
authenticationsValidator: AuthenticationsValidator,
devicesDAO: DevicesDAO
) {

def save(providerId: String, providerKey: String, udid: String, deviceType: DeviceType, userAgent: Option[String]): Future[AccountId] = {
for {
a <- authenticationsValidator.findAccountId(providerId, providerKey)
_ <- devicesDAO.create(udid, deviceType, userAgent, a.toSessionId)
} yield (a)
}


def update(udid: String, pushToken: Option[String], sessionId: SessionId): Future[Unit] = {
devicesDAO.update(udid, pushToken, sessionId).flatMap(_ => Future.Unit)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ class AccountsDAO @Inject()(db: DatabaseService) {
run(q)
}

def create(accountName: String, displayName: String): Future[AccountId] = {

val accountStatus = AccountStatusType.normally
val q = quote {
query[Accounts].insert(
_.accountName -> lift(accountName),
_.displayName -> lift(displayName),
_.accountStatus -> lift(accountStatus)
).returning(_.id)
}
run(q)
}

def updateProfile(displayName: String,
web: Option[String],
birthday: Option[Long],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class AuthenticationsDAO @Inject()(db: DatabaseService) {
run(q).map(_ => Unit)
}

def updateAccountId(providerId: String, providerKey: String, accountId: AccountId): Future[Unit] = {
def link(providerId: String, providerKey: String, accountId: AccountId): Future[Unit] = {
val q = quote {
query[Authentications]
.filter(_.providerId == lift(providerId))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.github.cactacea.backend.core.infrastructure.validators

import com.google.inject.{Inject, Singleton}
import com.twitter.util.Future
import io.github.cactacea.backend.core.infrastructure.dao.AuthenticationsDAO
import io.github.cactacea.backend.core.infrastructure.identifiers.AccountId
import io.github.cactacea.backend.core.util.exceptions.CactaceaException
import io.github.cactacea.backend.core.util.responses.CactaceaErrors._

@Singleton
class AuthenticationsValidator @Inject()(
authenticationsDAO: AuthenticationsDAO
) {

def findAccountId(providerId: String, providerKey: String): Future[AccountId] = {
authenticationsDAO.find(providerId, providerKey).flatMap(_ match {
case Some(a) =>
a.accountId match {
case Some(id) =>
Future.value(id)
case None =>
Future.exception(CactaceaException(AccountNotFound))
}
case None =>
Future.exception(CactaceaException(AccountNotFound))
})

}


}


Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ package io.github.cactacea.backend.core.util.configs

import java.net.InetAddress

import com.twitter.util.Duration
import com.twitter.conversions.DurationOps._
import com.twitter.conversions.StorageUnitOps._
import com.twitter.util.Duration
import com.typesafe.config.ConfigFactory
import io.github.cactacea.backend.core.domain.enums.DeviceType
import net.ceedubs.ficus.Ficus._
import net.ceedubs.ficus.readers.ArbitraryTypeReader._
import com.twitter.conversions.StorageUnitOps._

object Config extends DurationReader {

Expand All @@ -19,7 +19,8 @@ object Config extends DurationReader {
private val authConfig = config.as[AuthConfig]("auth")
private val passwordConfig = config.as[PasswordConfig]("password")
private val storageConfig = config.as[StorageConfig]("storage")

private val facebookConfig = config.as[OAuth2Config]("socials.facebook")
private val twitterConfig = config.as[OAuth1Config]("socials.twitte")
object db { // scalastyle:ignore

trait config {
Expand Down Expand Up @@ -110,11 +111,28 @@ object Config extends DurationReader {
lazy val keyLength = passwordConfig.keyLength.getOrElse(128)
}

object crypter {
object crypter { // scalastyle:ignore
lazy val signerKey = crypterConfig.signerKey.getOrElse("todo")
lazy val crypterKey = crypterConfig.crypterKey.getOrElse("todo")
}

object facebook { // scalastyle:ignore
val authorizationURL = facebookConfig.authorizationURL
val accessTokenURL = facebookConfig.accessTokenURL.getOrElse("")
val redirectURL = facebookConfig.redirectURL
val clientID = facebookConfig.clientID.getOrElse("")
val clientSecret = facebookConfig.clientSecret.getOrElse("")
val scope = facebookConfig.scope
}

object twitter { // scalastyle:ignore
val requestTokenURL = twitterConfig.requestTokenURL.getOrElse("")
val accessTokenURL = twitterConfig.accessTokenURL.getOrElse("")
val authorizationURL = twitterConfig.authorizationURL.getOrElse("")
val callbackURL = twitterConfig.callbackURL.getOrElse("")
val consumerKey = twitterConfig.consumerKey.getOrElse("")
val consumerSecret = twitterConfig.consumerSecret.getOrElse("")
}

println( // scalastyle:ignore
""" ___ _ ___ _ _
Expand Down Expand Up @@ -162,8 +180,20 @@ object Config extends DurationReader {
println(s"password.salt = ${password.salt}") // scalastyle:ignore
println(s"password.iterations = ${password.iterations}") // scalastyle:ignore
println(s"password.keyLength = ${password.keyLength}") // scalastyle:ignore
println(s"crypter.crypterKey = ${crypter.crypterKey}")
println(s"crypter.signerKey = ${crypter.signerKey}")
println(s"crypter.crypterKey = ${crypter.crypterKey}") // scalastyle:ignore
println(s"crypter.signerKey = ${crypter.signerKey}") // scalastyle:ignore
println(s"facebook.authorizationURL = ${facebook.authorizationURL}") // scalastyle:ignore
println(s"facebook.accessTokenURL = ${facebook.accessTokenURL}") // scalastyle:ignore
println(s"facebook.redirectURL = ${facebook.redirectURL}") // scalastyle:ignore
println(s"facebook.clientID = ${facebook.clientID}") // scalastyle:ignore
println(s"facebook.clientSecret = ${facebook.clientSecret}") // scalastyle:ignore
println(s"facebook.scope = ${facebook.scope}") // scalastyle:ignore
println(s"twitter.requestTokenURL = ${twitter.requestTokenURL}") // scalastyle:ignore
println(s"twitter.accessTokenURL = ${twitter.accessTokenURL}") // scalastyle:ignore
println(s"twitter.authorizationURL = ${twitter.authorizationURL}") // scalastyle:ignore
println(s"twitter.callbackURL = ${twitter.callbackURL}") // scalastyle:ignore
println(s"twitter.consumerKey = ${twitter.consumerKey}") // scalastyle:ignore
println(s"twitter.consumerSecret = ${twitter.consumerSecret}") // scalastyle:ignore
println("") // scalastyle:ignore

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.github.cactacea.backend.core.util.configs

case class OAuth1Config (
requestTokenURL: Option[String],
accessTokenURL: Option[String],
authorizationURL: Option[String],
callbackURL: Option[String],
consumerKey: Option[String],
consumerSecret: Option[String]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.github.cactacea.backend.core.util.configs

case class OAuth2Config (
authorizationURL: Option[String],
accessTokenURL: Option[String],
redirectURL: Option[String],
clientID: Option[String],
clientSecret: Option[String],
scope: Option[String]
)
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package io.github.cactacea.backend.core.domain.repositories

import io.github.cactacea.backend.core.domain.enums.{AccountStatusType, DeviceType, MediumType}
import io.github.cactacea.backend.core.domain.enums.{AccountStatusType, MediumType}
import io.github.cactacea.backend.core.helpers.RepositorySpec
import io.github.cactacea.backend.core.infrastructure.dao.{AccountsDAO, DevicesDAO, PushNotificationSettingsDAO}
import io.github.cactacea.backend.core.infrastructure.dao.{AccountsDAO, PushNotificationSettingsDAO}
import io.github.cactacea.backend.core.infrastructure.identifiers.{AccountId, MediumId}
import io.github.cactacea.backend.core.util.exceptions.CactaceaException
import io.github.cactacea.backend.core.util.responses.CactaceaErrors.{AccountNotFound, AccountTerminated, MediumNotFound, SessionTimeout}
Expand All @@ -11,7 +11,7 @@ class AccountsRepositorySpec extends RepositorySpec {

val blocksRepository = injector.instance[BlocksRepository]
val mediumRepository = injector.instance[MediumsRepository]
val devicesDAO = injector.instance[DevicesDAO]
// val devicesDAO = injector.instance[DevicesDAO]
var notificationSettingsDAO = injector.instance[PushNotificationSettingsDAO]
val accountsDAO = injector.instance[AccountsDAO]

Expand All @@ -20,10 +20,10 @@ class AccountsRepositorySpec extends RepositorySpec {
val accountName = "SessionsRepositorySpec2"
val displayName = "SessionsRepositorySpec2"
// val password = "password"
val udid = "0123456789012345678901234567890123456789"
val userAgent = Some("userAgent")
val result = execute(accountsRepository.create(accountName, udid, DeviceType.ios, userAgent))
val account = execute(accountsRepository.find(result.accountName, udid, DeviceType.ios, userAgent))
// val udid = "0123456789012345678901234567890123456789"
// val userAgent = Some("userAgent")
val result = execute(accountsRepository.create(accountName))
val account = execute(accountsRepository.find(result.id.toSessionId))

assert(account.displayName == displayName)

Expand All @@ -48,8 +48,8 @@ class AccountsRepositorySpec extends RepositorySpec {
val accountName = "SessionsRepositorySpec4"
// val password = "password"
val udid = "0123456789012345678901234567890123456789"
val userAgent = Some("userAgent")
val session = execute(accountsRepository.create(accountName, udid, DeviceType.ios, userAgent))
// val userAgent = Some("userAgent")
val session = execute(accountsRepository.create(accountName))
execute(accountsRepository.signOut(udid, session.id.toSessionId))

}
Expand All @@ -60,16 +60,16 @@ class AccountsRepositorySpec extends RepositorySpec {
val displayName = "SessionsRepositorySpec1"
// val password = "password"
val udid = "0123456789012345678901234567890123456789"
val userAgent = Some("userAgent")
val account = execute(accountsRepository.create(accountName, udid, DeviceType.ios, userAgent))
// val userAgent = Some("userAgent")
val account = execute(accountsRepository.create(accountName))

// result user
assert(account.accountName == accountName)
assert(account.displayName == displayName)

// result device
val devices = execute(devicesDAO.exist(account.id.toSessionId, udid))
assert(devices == true)
// // result device
// val devices = execute(devicesDAO.exist(account.id.toSessionId, udid))
// assert(devices == true)

// result notificationSettings
val notificationSettings = execute(notificationSettingsDAO.find(account.id.toSessionId))
Expand Down Expand Up @@ -267,8 +267,8 @@ class AccountsRepositorySpec extends RepositorySpec {
val accountName = "SessionsRepositorySpec5"
// val password = "password"
val udid = "0123456789012345678901234567890123456789"
val userAgent = Some("userAgent")
val session = execute(accountsRepository.create(accountName, udid, DeviceType.ios, userAgent))
// val userAgent = Some("userAgent")
val session = execute(accountsRepository.create(accountName))

val expired = System.currentTimeMillis()
execute(accountsRepository.find(session.id.toSessionId, expired))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import io.github.cactacea.backend.core.infrastructure.dao.DevicesDAO
class DevicesRepositorySpec extends RepositorySpec {

val devicesRepository = injector.instance[DevicesRepository]
val devicesDAO = injector.instance[DevicesDAO]

test("updateDeviceToken") {

Expand Down
Loading

0 comments on commit c5318cb

Please sign in to comment.