Merge branch 'develop' of github.com:OpenBankProject/OBP-API into develop

This commit is contained in:
Simon Redfern 2022-08-31 15:47:15 +02:00
commit 9ab4a7df7d
29 changed files with 683 additions and 338 deletions

View File

@ -99,18 +99,22 @@
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-text -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.8</version>
<version>42.4.1</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
@ -220,7 +224,7 @@
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.8.17</version>
<version>7.17.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sksamuel.elastic4s/elastic4s-client-esjava -->
<dependency>
@ -330,11 +334,21 @@
<artifactId>oauth2-oidc-sdk</artifactId>
<version>9.27</version>
</dependency>
<!-- ********** flexmark START ********** -->
<!-- Library flexmark-all v0.40.8 is replaced with used modules -->
<!-- https://mvnrepository.com/artifact/com.vladsch.flexmark/flexmark-profile-pegdown -->
<dependency>
<groupId>com.vladsch.flexmark</groupId>
<artifactId>flexmark-all</artifactId>
<artifactId>flexmark-profile-pegdown</artifactId>
<version>0.40.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.vladsch.flexmark/flexmark-util-options -->
<dependency>
<groupId>com.vladsch.flexmark</groupId>
<artifactId>flexmark-util-options</artifactId>
<version>0.64.0</version>
</dependency>
<!-- ********** flexmark END ********** -->
<!--scala utils, for type scan-->
<dependency>
<groupId>org.clapper</groupId>
@ -355,11 +369,11 @@
<scope>test</scope>
</dependency>
<!-- embeded kafka for unit test end -->
<!-- https://mvnrepository.com/artifact/com.nexmo/client -->
<!-- https://mvnrepository.com/artifact/com.twilio.sdk/twilio -->
<dependency>
<groupId>com.nexmo</groupId>
<artifactId>client</artifactId>
<version>4.0.1</version>
<groupId>com.twilio.sdk</groupId>
<artifactId>twilio</artifactId>
<version>8.34.1</version>
</dependency>
<dependency>
<groupId>io.swagger.parser.v3</groupId>
@ -397,10 +411,11 @@
<artifactId>scalapb-runtime-grpc_${scala.version}</artifactId>
<version>0.8.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.grpc/grpc-all -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-all</artifactId>
<version>1.25.0</version>
<version>1.48.1</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>

View File

@ -8,7 +8,8 @@ invalid.zip.code = Invalid ZIP code
invalid.postal.code = Invalid postal code
unique.email.address = The email address must be unique
must.be.logged.in = You must be logged in
already.logged.in = already logged in. Please logout first.
already.logged.in = Please logout first
already.logged.in.title = You are already logged in
login = Login
logout = Logout
log.in = Log In

View File

@ -854,7 +854,7 @@ database_messages_scheduler_interval=3600
# ---------------------------------------------------------
# -- SCA (Strong Customer Authentication) -------
# For now, OBP-API use `nexmo` server as the SMS provider. Please check `nexmo` website, and get the api key and value there.
# For now, OBP-API use `Twilio` server as the SMS provider. Please check `Twilio` website, and get the api key and value there.
# sca_phone_api_key = oXAjqAJ6rvCunpzN
# sca_phone_api_secret =oXAjqAJ6rvCunpzN123sdf
#

View File

@ -539,6 +539,7 @@ class Boot extends MdcLoggable {
Menu("User Invitation Info", "User Invitation Info") / "user-invitation-info",
Menu("User Invitation Invalid", "User Invitation Invalid") / "user-invitation-invalid",
Menu("User Invitation Warning", "User Invitation Warning") / "user-invitation-warning",
Menu("Already Logged In", "Already Logged In") / "already-logged-in",
Menu("Terms and Conditions", "Terms and Conditions") / "terms-and-conditions",
Menu("Privacy Policy", "Privacy Policy") / "privacy-policy",
// Menu.i("Metrics") / "metrics", //TODO: allow this page once we can make the account number anonymous in the URL
@ -725,6 +726,7 @@ class Boot extends MdcLoggable {
val auditor = Views.views.vend.getOrCreateSystemView(SYSTEM_AUDITOR_VIEW_ID).isDefined
val accountant = Views.views.vend.getOrCreateSystemView(SYSTEM_ACCOUNTANT_VIEW_ID).isDefined
val smallPaymentVerified = Views.views.vend.getOrCreateSystemView(SYSTEM_SMALL_PAYMENT_VERIFIED_VIEW_ID).isDefined
val accountHolder = Views.views.vend.getOrCreateSystemView(SYSTEM_STAGE_ONE_VIEW_ID).isDefined
// Only create Firehose view if they are enabled at instance.
val accountFirehose = if (ApiPropsWithAlias.allowAccountFirehose)
Views.views.vend.getOrCreateSystemView(SYSTEM_FIREHOSE_VIEW_ID).isDefined
@ -737,6 +739,7 @@ class Boot extends MdcLoggable {
|System view ${SYSTEM_ACCOUNTANT_VIEW_ID} exists/created at the instance: ${accountant}
|System view ${SYSTEM_FIREHOSE_VIEW_ID} exists/created at the instance: ${accountFirehose}
|System view ${SYSTEM_SMALL_PAYMENT_VERIFIED_VIEW_ID} exists/created at the instance: ${smallPaymentVerified}
|System view ${SYSTEM_STAGE_ONE_VIEW_ID} exists/created at the instance: ${accountHolder}
|""".stripMargin
logger.info(comment)

View File

@ -29,6 +29,7 @@ object Constant extends MdcLoggable {
final val SYSTEM_ACCOUNTANT_VIEW_ID = "accountant"
final val SYSTEM_FIREHOSE_VIEW_ID = "firehose"
final val SYSTEM_SMALL_PAYMENT_VERIFIED_VIEW_ID = "SmallPaymentVerified"
final val SYSTEM_STAGE_ONE_VIEW_ID = "StageOne"
final val SYSTEM_READ_ACCOUNTS_BASIC_VIEW_ID = "ReadAccountsBasic"
final val SYSTEM_READ_ACCOUNTS_DETAIL_VIEW_ID = "ReadAccountsDetail"
final val SYSTEM_READ_BALANCES_VIEW_ID = "ReadBalances"

View File

@ -6,7 +6,7 @@ import code.DynamicEndpoint.{DynamicEndpointProvider, DynamicEndpointT}
import code.api.util.APIUtil.{BigDecimalBody, BigIntBody, BooleanBody, DoubleBody, EmptyBody, FloatBody, IntBody, JArrayBody, LongBody, PrimaryDataBody, ResourceDoc, StringBody}
import code.api.util.ApiTag._
import code.api.util.ErrorMessages.{DynamicDataNotFound, InvalidUrlParameters, UnknownError, UserHasMissingRoles, UserNotLoggedIn}
import code.api.util.{APIUtil, ApiRole, ApiTag, CustomJsonFormats, NewStyle}
import code.api.util.{APIUtil, ApiRole, ApiTag, CommonUtil, CustomJsonFormats, NewStyle}
import com.openbankproject.commons.util.{ApiShortVersions, ApiStandards, ApiVersion}
import com.openbankproject.commons.util.Functions.Memo
import io.swagger.v3.oas.models.PathItem.HttpMethod
@ -25,7 +25,6 @@ import net.liftweb.json.JsonDSL._
import net.liftweb.json.JsonParser.ParseException
import org.apache.commons.lang3.{StringUtils, Validate}
import net.liftweb.util.{StringHelpers, ThreadGlobal}
import org.apache.commons.collections4.{ListUtils, MapUtils}
import org.apache.commons.io.FileUtils
import org.apache.commons.lang3.StringUtils
@ -765,10 +764,10 @@ object DynamicEndpointHelper extends RestHelper {
// "title": "accountTransactibility",
// "type": "object"
// }
case v if v.isInstanceOf[ObjectSchema] && MapUtils.isEmpty(v.getProperties()) =>
case v if v.isInstanceOf[ObjectSchema] && CommonUtil.Map.isEmpty(v.getProperties()) =>
EmptyBody
case v if v.isInstanceOf[ObjectSchema] || MapUtils.isNotEmpty(v.getProperties()) =>
case v if v.isInstanceOf[ObjectSchema] || CommonUtil.Map.isNotEmpty(v.getProperties()) =>
val properties: util.Map[String, Schema[_]] = v.getProperties
val jFields: mutable.Iterable[JField] = properties.asScala.map { kv =>

View File

@ -0,0 +1,17 @@
package code.api.util
import java.util
// Introduced in order to replace library: https://mvnrepository.com/artifact/org.apache.commons/commons-collections4/4.4
// which contains vulnerabilities from dependencies:
// CVE-2020-15250
object CommonUtil {
object Collections {
def isEmpty(coll: util.Collection[_]): Boolean = coll == null || coll.isEmpty
def isNotEmpty(coll: util.Collection[_]): Boolean = !isEmpty(coll)
}
object Map {
def isEmpty(map: java.util.Map[_, _]): Boolean = map == null || map.isEmpty
def isNotEmpty(map: java.util.Map[_, _]): Boolean = !isEmpty(map)
}
}

View File

@ -37,8 +37,8 @@ object I18NUtil {
object ResourceDocTranslation {
def summary(operationId: String, language: Option[LanguageParam], default: String): String = {
language match {
case Some(value) =>
val webUiKey = s"webui_resource_doc_operation_id_${operationId}_summary_${value}"
case Some(locale) =>
val webUiKey = s"webui_resource_doc_operation_id_${operationId}_summary_${locale}"
getWebUiPropsValue(webUiKey, default)
case None =>
default
@ -46,8 +46,8 @@ object I18NUtil {
}
def description(operationId: String, language: Option[LanguageParam], default: String): String = {
language match {
case Some(value) =>
val webUiKey = s"webui_resource_doc_operation_id_${operationId}_description_${value}"
case Some(locale) =>
val webUiKey = s"webui_resource_doc_operation_id_${operationId}_description_${locale}"
getWebUiPropsValue(webUiKey, default)
case None =>
default

View File

@ -1,6 +1,5 @@
package code.api.util
import com.vladsch.flexmark.convert.html.FlexmarkHtmlParser
import com.vladsch.flexmark.html.HtmlRenderer
import com.vladsch.flexmark.parser.Parser
import com.vladsch.flexmark.profiles.pegdown.Extensions
@ -42,9 +41,4 @@ object PegdownOptions {
val document = parser.parse(description.stripMargin)
renderer.render(document)
}
def convertHtmlMarkdown(html: String): String = {
//TODO, this is a simple version, may add more options later.
FlexmarkHtmlParser.parse(html)
}
}

View File

@ -39,8 +39,6 @@ import code.views.Views
import code.webhook.AccountWebhook
import code.webuiprops.{MappedWebUiPropsProvider, WebUiPropsCommons}
import com.github.dwickern.macros.NameOf.nameOf
import com.nexmo.client.NexmoClient
import com.nexmo.client.sms.messages.TextMessage
import com.openbankproject.commons.model.enums.{AccountAttributeType, CardAttributeType, ProductAttributeType, StrongCustomerAuthentication}
import com.openbankproject.commons.model.{CreditLimit, Product, _}
import com.openbankproject.commons.util.{ApiVersion, ReflectUtils}

View File

@ -2,6 +2,7 @@ package code.api.v4_0_0
import java.net.URLEncoder
import java.text.SimpleDateFormat
import java.util
import java.util.{Calendar, Date}
import code.DynamicData.{DynamicData, DynamicDataProvider}
@ -71,6 +72,7 @@ import code.views.Views
import code.webhook.{AccountWebhook, BankAccountNotificationWebhookTrait, SystemAccountNotificationWebhookTrait}
import code.webuiprops.MappedWebUiPropsProvider.getWebUiPropsValue
import com.github.dwickern.macros.NameOf.nameOf
import com.networknt.schema.ValidationMessage
import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.dto.GetProductsParam
import com.openbankproject.commons.model.enums.ChallengeType.OBP_TRANSACTION_REQUEST_CHALLENGE
@ -90,7 +92,6 @@ import net.liftweb.mapper.By
import net.liftweb.util.Helpers.{now, tryo}
import net.liftweb.util.Mailer.{From, PlainMailBodyType, Subject, To, XHTMLMailBodyType}
import net.liftweb.util.{Helpers, Mailer, StringHelpers}
import org.apache.commons.collections4.CollectionUtils
import org.apache.commons.lang3.StringUtils
import scala.collection.immutable.{List, Nil}
@ -4199,11 +4200,12 @@ trait APIMethods400 {
cc =>
val failMsg = s"$InvalidJsonFormat The Json body should be the $PostAccountAccessJsonV400 "
for {
(Full(u), callContext) <- SS.user
postJson <- NewStyle.function.tryons(failMsg, 400, cc.callContext) {
json.extract[PostAccountAccessJsonV400]
}
_ <- NewStyle.function.canGrantAccessToView(bankId, accountId, cc.loggedInUser, cc.callContext)
(user, callContext) <- NewStyle.function.findByUserId(postJson.user_id, cc.callContext)
_ <- NewStyle.function.canGrantAccessToView(bankId, accountId, u, callContext)
(user, callContext) <- NewStyle.function.findByUserId(postJson.user_id, callContext)
view <- getView(bankId, accountId, postJson.view, callContext)
addedView <- grantAccountAccessToUser(bankId, accountId, user, view, callContext)
} yield {
@ -9417,9 +9419,9 @@ trait APIMethods400 {
for {
(Full(u), callContext) <- SS.user
schemaErrors = JsonSchemaUtil.validateSchema(httpBody)
schemaErrors: util.Set[ValidationMessage] = JsonSchemaUtil.validateSchema(httpBody)
_ <- Helper.booleanToFuture(failMsg = s"$JsonSchemaIllegal${StringUtils.join(schemaErrors, "; ")}", cc=callContext) {
CollectionUtils.isEmpty(schemaErrors)
CommonUtil.Collections.isEmpty(schemaErrors)
}
(isExists, callContext) <- NewStyle.function.isJsonSchemaValidationExists(operationId, callContext)
@ -9465,7 +9467,7 @@ trait APIMethods400 {
schemaErrors = JsonSchemaUtil.validateSchema(httpBody)
_ <- Helper.booleanToFuture(failMsg = s"$JsonSchemaIllegal${StringUtils.join(schemaErrors, "; ")}", cc=callContext) {
CollectionUtils.isEmpty(schemaErrors)
CommonUtil.Collections.isEmpty(schemaErrors)
}
(isExists, callContext) <- NewStyle.function.isJsonSchemaValidationExists(operationId, callContext)

View File

@ -12,8 +12,8 @@ import net.sf.cglib.proxy.{Enhancer, MethodInterceptor, MethodProxy}
import java.lang.reflect.Method
import code.api.util.{CallContext, DynamicUtil}
import com.auth0.jwt.internal.org.apache.commons.lang3.StringEscapeUtils
import org.apache.commons.lang3.StringUtils
import org.apache.commons.text.StringEscapeUtils
import com.github.dwickern.macros.NameOf.{nameOf, qualifiedNameOfType}
import com.openbankproject.commons.util.ReflectUtils

View File

@ -74,8 +74,6 @@ import code.util.Helper
import code.util.Helper.{MdcLoggable, _}
import code.views.Views
import com.google.common.cache.CacheBuilder
import com.nexmo.client.NexmoClient
import com.nexmo.client.sms.messages.TextMessage
import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.dto.{CustomerAndAttribute, GetProductsParam, ProductCollectionItemsTree}
import com.openbankproject.commons.model.enums.ChallengeType.OBP_TRANSACTION_REQUEST_CHALLENGE
@ -86,6 +84,10 @@ import com.openbankproject.commons.model.enums.{TransactionRequestStatus, _}
import com.openbankproject.commons.model.{AccountApplication, AccountAttribute, DirectDebitTrait, FXRate, Product, ProductAttribute, ProductCollectionItem, TaxResidence, TransactionRequestCommonBodyJSON, _}
import com.tesobe.CacheKeyFromArguments
import com.tesobe.model.UpdateBankAccount
import com.twilio.Twilio
import com.twilio.rest.api.v2010.account.Message
import com.twilio.`type`.PhoneNumber
import net.liftweb.common._
import net.liftweb.json
import net.liftweb.json.JsonAST.JField
@ -340,19 +342,12 @@ object LocalMappedConnector extends Connector with MdcLoggable {
for {
smsProviderApiKey <- APIUtil.getPropsValue("sca_phone_api_key") ?~! s"$MissingPropsValueAtThisInstance sca_phone_api_key"
smsProviderApiSecret <- APIUtil.getPropsValue("sca_phone_api_secret") ?~! s"$MissingPropsValueAtThisInstance sca_phone_api_secret"
client = new NexmoClient.Builder()
.apiKey(smsProviderApiKey)
.apiSecret(smsProviderApiSecret)
.build();
client = Twilio.init(smsProviderApiKey, smsProviderApiSecret)
phoneNumber = tuple._2
messageText = s"Your consent challenge : ${challengeAnswer}";
message = new TextMessage("OBP-API", phoneNumber, messageText);
response <- tryo(client.getSmsClient().submitMessage(message))
failMsg = s"$SmsServerNotResponding: $phoneNumber. Or Please to use EMAIL first."
_ <- Helper.booleanToBox(
response.getMessages.get(0).getStatus == com.nexmo.client.sms.MessageStatus.OK,
failMsg
)
message: Box[Message] = tryo(Message.creator(new PhoneNumber(phoneNumber), new PhoneNumber(phoneNumber), messageText).create())
failMsg = s"$SmsServerNotResponding: $phoneNumber. Or Please to use EMAIL first. ${message.map(_.getErrorMessage).getOrElse("")}"
_ <- Helper.booleanToBox(message.forall(_.getErrorMessage.isEmpty), failMsg)
} yield true
}
val errorMessage = sendingResult.filter(_.isInstanceOf[Failure]).map(_.asInstanceOf[Failure].msg)
@ -867,44 +862,97 @@ object LocalMappedConnector extends Connector with MdcLoggable {
MultipleConnectionPoolContext(ConnectionPool.DEFAULT_NAME -> connectionPool)
}
private def findFirehoseAccounts(bankId: BankId, ordering: SQLSyntax, limit: Int, offset: Int)(implicit session: DBSession = AutoSession) = {
val sqlResult = sql"""
|select
| mappedbankaccount.theaccountid as account_id,
| mappedbankaccount.bank as bank_id,
| mappedbankaccount.accountlabel as account_label,
| mappedbankaccount.accountnumber as account_number,
| (select
| string_agg(
| 'user_id:'
| || resourceuser.userid_
| ||',provider:'
| ||resourceuser.provider_
| ||',user_name:'
| ||resourceuser.name_,
| ',') as owners
| from resourceuser
| where
| resourceuser.id = mapperaccountholders.user_c
| ),
| mappedbankaccount.kind as kind,
| mappedbankaccount.accountcurrency as account_currency ,
| mappedbankaccount.accountbalance as account_balance,
| (select
| string_agg(
| 'bank_id:'
| ||bankaccountrouting.bankid
| ||',account_id:'
| ||bankaccountrouting.accountid,
| ','
| ) as account_routings
| from bankaccountrouting
| where
| bankaccountrouting.accountid = mappedbankaccount.theaccountid
| ),
| (select
| string_agg(
| 'type:'
| || mappedaccountattribute.mtype
| ||',code:'
| ||mappedaccountattribute.mcode
| ||',value:'
| ||mappedaccountattribute.mvalue,
| ',') as account_attributes
| from mappedaccountattribute
| where
| mappedaccountattribute.maccountid = mappedbankaccount.theaccountid
| )
|from mappedbankaccount
| LEFT JOIN mapperaccountholders
| ON (mappedbankaccount.bank = mapperaccountholders.accountbankpermalink and mappedbankaccount.theaccountid = mapperaccountholders.accountpermalink)
|WHERE mappedbankaccount.bank = ${bankId.value}
|ORDER BY mappedbankaccount.theaccountid $ordering
|LIMIT $limit
|OFFSET $offset ;
|
|
|""".stripMargin
.map(
rs => // Map result to case class
FastFirehoseAccount(
id = rs.stringOpt(1).map(_.toString).getOrElse(null),
bankId= rs.stringOpt(2).map(_.toString).getOrElse(null),
label= rs.stringOpt(3).map(_.toString).getOrElse(null),
number = rs.stringOpt(4).map(_.toString).getOrElse(null),
owners = rs.stringOpt(5).map(_.toString).getOrElse(null),
productCode = rs.stringOpt(6).map(_.toString).getOrElse(null),
balance = AmountOfMoney(
currency = rs.stringOpt(7).map(_.toString).getOrElse(null),
amount = rs.stringOpt(8).map(_.toString).getOrElse(null)
),
accountRoutings = rs.stringOpt(9).map(_.toString).getOrElse(null),
accountAttributes = rs.stringOpt(10).map(_.toString).getOrElse(null)
)
).list().apply()
sqlResult
}
override def getBankAccountsWithAttributes(bankId: BankId, queryParams: List[OBPQueryParam], callContext: Option[CallContext]): OBPReturnType[Box[List[FastFirehoseAccount]]] =
Future{
val limit = queryParams.collect { case OBPLimit(value) => value }.headOption.getOrElse(50)
val limit: Int = queryParams.collect { case OBPLimit(value) => value }.headOption.getOrElse(50)
val offset = queryParams.collect { case OBPOffset(value) => value }.headOption.getOrElse(0)
val orderBy = queryParams.collect {
case OBPOrdering(_, OBPDescending) => "DESC"
}.headOption.getOrElse("ASC")
val ordering = if (orderBy =="DESC" ) sqls"DESC" else sqls"ASC"
val ordering: SQLSyntax = if (orderBy =="DESC" ) sqls"DESC" else sqls"ASC"
val firehoseAccounts = {
scalikeDB readOnly { implicit session =>
val sqlResult = sql"""
select * from mv_fast_firehose_accounts
WHERE mv_fast_firehose_accounts.bank_id = ${bankId.value}
ORDER BY mv_fast_firehose_accounts.account_id $ordering
LIMIT $limit
OFFSET $offset
""".stripMargin
.map(
rs => // Map result to case class
FastFirehoseAccount(
id = rs.stringOpt(1).map(_.toString).getOrElse(null),
bankId= rs.stringOpt(2).map(_.toString).getOrElse(null),
label= rs.stringOpt(3).map(_.toString).getOrElse(null),
number = rs.stringOpt(4).map(_.toString).getOrElse(null),
owners = rs.stringOpt(5).map(_.toString).getOrElse(null),
productCode = rs.stringOpt(6).map(_.toString).getOrElse(null),
balance = AmountOfMoney(
currency = rs.stringOpt(7).map(_.toString).getOrElse(null),
amount = rs.stringOpt(8).map(_.toString).getOrElse(null)
),
accountRoutings = rs.stringOpt(9).map(_.toString).getOrElse(null),
accountAttributes = rs.stringOpt(10).map(_.toString).getOrElse(null)
)
).list().apply()
sqlResult
findFirehoseAccounts(bankId, ordering, limit, offset)
}
}
(Full(firehoseAccounts), callContext)
@ -5467,15 +5515,14 @@ object LocalMappedConnector extends Connector with MdcLoggable {
smsProviderApiSecret <- NewStyle.function.tryons(failMsg, 400, callContext) {
APIUtil.getPropsValue("sca_phone_api_secret").openOrThrowException(s"")
}
client = new NexmoClient.Builder()
.apiKey(smsProviderApiKey)
.apiSecret(smsProviderApiSecret)
.build();
messageSent = new TextMessage("OBP-API", phoneNumber, message);
response <- Future{client.getSmsClient().submitMessage(messageSent)}
client = Twilio.init(smsProviderApiKey, smsProviderApiSecret)
failMsg = s"$SmsServerNotResponding: $phoneNumber. Or Please to use EMAIL first."
messageSent: Message <- NewStyle.function.tryons(failMsg,400, callContext) {
Message.creator(new PhoneNumber(phoneNumber), new PhoneNumber(phoneNumber), message).create()
}
failMsg = messageSent.getErrorMessage
_ <- Helper.booleanToFuture(failMsg, cc=callContext) {
response.getMessages.get(0).getStatus == com.nexmo.client.sms.MessageStatus.OK
messageSent.getErrorMessage.isEmpty
}
}yield Future{(Full("Success"), callContext)}
} else

View File

@ -38,8 +38,9 @@ import code.bankconnectors.Connector
import code.context.UserAuthContextProvider
import code.entitlement.Entitlement
import code.loginattempts.LoginAttempt
import code.snippet.WebUI
import code.token.TokensOpenIDConnect
import code.users.Users
import code.users.{UserAgreementProvider, Users}
import code.util.Helper
import code.util.Helper.MdcLoggable
import code.views.Views
@ -59,7 +60,9 @@ import code.util.HydraUtil._
import com.github.dwickern.macros.NameOf.nameOf
import sh.ory.hydra.model.AcceptLoginRequest
import net.liftweb.http.S.fmapFunc
import net.liftweb.sitemap.Loc.{If, LocParam, Template}
import sh.ory.hydra.api.AdminApi
import net.liftweb.sitemap.Loc.strToFailMsg
import scala.concurrent.Future
@ -643,6 +646,13 @@ import net.liftweb.util.Helpers._
override def actionsAfterSignup(theUser: TheUserType, func: () => Nothing): Nothing = {
theUser.setValidated(skipEmailValidation).resetUniqueId()
theUser.save
val privacyPolicyValue: String = getWebUiPropsValue("webui_privacy_policy", "")
val termsAndConditionsValue: String = getWebUiPropsValue("webui_terms_and_conditions", "")
// User Agreement table
UserAgreementProvider.userAgreementProvider.vend.createOrUpdateUserAgreement(
theUser.user.foreign.map(_.userId).getOrElse(""), "privacy_conditions", privacyPolicyValue)
UserAgreementProvider.userAgreementProvider.vend.createOrUpdateUserAgreement(
theUser.user.foreign.map(_.userId).getOrElse(""), "terms_and_conditions", termsAndConditionsValue)
if (!skipEmailValidation) {
sendValidationEmail(theUser)
S.notice(S.?("sign.up.message"))
@ -664,17 +674,20 @@ import net.liftweb.util.Helpers._
def agreeTermsDiv = {
val agreeTermsHtml = getWebUiPropsValue("webui_agree_terms_html", "")
if(agreeTermsHtml.isEmpty){
val url = getWebUiPropsValue("webui_agree_terms_url", "")
if (url.isEmpty) {
s""
} else {
scala.xml.Unparsed(s"""<div id="signup-agree-terms" class="checkbox"><label><input type="checkbox" />I hereby agree to the <a href="$url" title="T &amp; C">Terms and Conditions</a></label></div>""")
}
} else{
scala.xml.Unparsed(s"""$agreeTermsHtml""")
}
val webUi = new WebUI
val webUiPropsValue = getWebUiPropsValue("webui_terms_and_conditions", "")
val agreeTermsHtml = s"""<hr>
| <div class="form-group" id="terms-and-conditions-div" onclick="enableDisableButton()">
| <details open style="cursor:s-resize;">
| <summary style="display:list-item;"><a class="api_group_name">Terms and Conditions</a></summary>
| <div id="terms-and-conditions-page">${webUi.makeHtml(webUiPropsValue)}</div>
| </details>
| <input type="checkbox" class="form-check-input" id="terms_checkbox" >
| <label id="terms_checkbox_value" class="form-check-label" for="terms_checkbox">I agree to the above Developer Terms and Conditions</label>
| </div>
| """.stripMargin
scala.xml.Unparsed(agreeTermsHtml)
}
def legalNoticeDiv = {
@ -687,13 +700,36 @@ import net.liftweb.util.Helpers._
}
def agreePrivacyPolicy = {
val url = getWebUiPropsValue("webui_agree_privacy_policy_url", "")
val text = getWebUiPropsValue("webui_agree_privacy_policy_html_text", s"""<div id="signup-agree-privacy-policy"><label>By submitting this information you consent to processing your data by TESOBE GmbH according to our <a href="$url" title="Privacy Policy">Privacy Policy</a>. TESOBE shall use this information to send you emails and provide customer support.</label></div>""")
if (url.isEmpty) {
s""
} else {
scala.xml.Unparsed(s"""$text""")
}
val webUi = new WebUI
val webUiPropsValue = getWebUiPropsValue("webui_privacy_policy", "")
val agreePrivacyPolicy = s"""<hr>
| <div class="form-group" id="privacy-conditions-div" onclick="enableDisableButton()">
| <details open style="cursor:s-resize;">
| <summary style="display:list-item;"><a class="api_group_name">Privacy Policy</a></summary>
| <div id="privacy-policy-page">${webUi.makeHtml(webUiPropsValue)}</div>
| </details>
| <input id="privacy_checkbox" type="checkbox" class="form-check-input">
| <label class="form-check-label" for="privacy_checkbox">I agree to the above privacy conditions</label>
| </div>
| <hr>""".stripMargin
scala.xml.Unparsed(agreePrivacyPolicy)
}
def enableDisableSignUpButton = {
val javaScriptCode = """<script>
| function enableDisableButton() {
| var checkBox = document.getElementById("terms-and-conditions-div").querySelector("input[type=checkbox]");
| var checkBox2 = document.getElementById("privacy-conditions-div").querySelector("input[type=checkbox]");
| var button = document.getElementById("submit-button");
| if (checkBox.checked == true && checkBox2.checked == true){
| button.disabled = false;
| } else {
| button.disabled = true;
| }
| }
| </script>""".stripMargin
scala.xml.Unparsed(javaScriptCode)
}
def signupFormTitle = getWebUiPropsValue("webui_signup_form_title_text", S.?("sign.up"))
@ -708,8 +744,9 @@ import net.liftweb.util.Helpers._
{agreeTermsDiv}
{agreePrivacyPolicy}
<div id="signup-submit">
<input type="submit" />
<input onmouseover="enableDisableButton()" onfocus="enableDisableButton()" disabled="true" id="submit-button" type="submit" class="btn btn-danger"/>
</div>
{enableDisableSignUpButton}
</form>
</div>
}
@ -931,6 +968,19 @@ def restoreSomeSessions(): Unit = {
override protected def capturePreLoginState(): () => Unit = () => {restoreSomeSessions}
/**
* The LocParams for the menu item for login.
* Overridden in order to add custom error message. Attention: Not calling super will change the default behavior!
*/
override protected def loginMenuLocParams: List[LocParam[Unit]] = {
org.scalameta.logger.elem(S.queryString)
If(notLoggedIn_? _, () => RedirectResponse("/already-logged-in")) ::
Template(() => wrapIt(login)) ::
Nil
}
//overridden to allow a redirection if login fails
/**
* Success cases:

View File

@ -263,6 +263,22 @@ class WebUI extends MdcLoggable{
"#webui-support-email a *" #> scala.xml.Unparsed(webUiPropsValue) &
"#webui-support-email a [href]" #> scala.xml.Unparsed(s"mailto:$webUiPropsValue")
}
def socialLink = {
val webUiPropsValueForLink = getWebUiPropsValue("webui_social_url", "https://twitter.com/openbankproject")
val webUiPropsValueForHandle = getWebUiPropsValue("webui_social_handle", "Twitter")
val webUiPropsValueForTitle = getWebUiPropsValue("webui_social_title", "@OpenBankProject")
val webUiPropsValueForLogoUrl = getWebUiPropsValue("webui_social_logo_url", "/media/images/icons/support/twitter.svg")
"#footer-social-logo-url img [src]" #> scala.xml.Unparsed(webUiPropsValueForLogoUrl) &
"#footer-social-handle *" #> scala.xml.Unparsed(webUiPropsValueForHandle) &
"#footer-social-link a *" #> scala.xml.Unparsed(webUiPropsValueForTitle) &
"#footer-social-link a [href]" #> scala.xml.Unparsed(webUiPropsValueForLink)
}
def footerSocialLink = {
val webUiPropsValueForLink = getWebUiPropsValue("webui_social_url", "https://twitter.com/openbankproject")
val webUiPropsValueForTitle = getWebUiPropsValue("webui_social_title", "Twitter")
"#footer-div-social a *" #> scala.xml.Unparsed(webUiPropsValueForTitle) &
"#footer-div-social a [href]" #> scala.xml.Unparsed(webUiPropsValueForLink)
}
def sandboxIntroductionLink: CssSel = {
val webUiApiDocumentation = getWebUiPropsValue("webui_api_documentation_url",s"${getServerUrl}/introduction")
@ -407,7 +423,11 @@ class WebUI extends MdcLoggable{
"@for-banks [style]" #> s"display: $displayForBanks"
}
def alreadyLoggedIn: CssSel = {
lazy val logoutLink = s" ${Constant.HostName}${AuthUser.logoutPath.foldLeft("")(_ + "/" + _)}"
lazy val loginLink = s" ${Constant.HostName}${AuthUser.loginPath.foldLeft("")(_ + "/" + _)}"
"#logout_link [href]" #> scala.xml.Unparsed(s"$logoutLink?redirect=$loginLink")
}
def getStartedContentLoader: NodeSeq = {
contentLoader("webui_get_started_content_url", "main-get-started")

View File

@ -3,12 +3,11 @@ package code.util
import java.nio.charset.Charset
import java.util.{Set => JSet}
import code.api.util.CallContext
import code.validation.{JsonValidation, JsonSchemaValidationProvider}
import code.api.util.{CallContext, CommonUtil}
import code.validation.{JsonSchemaValidationProvider, JsonValidation}
import com.fasterxml.jackson.databind.{JsonNode, ObjectMapper}
import com.google.common.hash.Hashing
import com.networknt.schema.{JsonSchema, JsonSchemaFactory, SpecVersionDetector, ValidationMessage}
import org.apache.commons.collections4.CollectionUtils
import org.apache.commons.lang3.StringUtils
object JsonSchemaUtil {
@ -47,7 +46,7 @@ object JsonSchemaUtil {
requestBody <- callContext.flatMap(_.httpBody)
JsonValidation(_, jsonSchema) <- JsonSchemaValidationProvider.validationProvider.vend.getByOperationId(operationIdBuilder)
errorSet = JsonSchemaUtil.validateJson(jsonSchema, requestBody)
if CollectionUtils.isNotEmpty(errorSet)
if CommonUtil.Collections.isNotEmpty(errorSet)
errorInfo = StringUtils.join(errorSet, "; ")
} yield errorInfo
}

View File

@ -898,7 +898,7 @@ object MapperViews extends Views with MdcLoggable {
def unsavedSystemView(name: String) : ViewDefinition = {
val entity = create
.isSystem_(true)
.isFirehose_(true) // TODO This should be set to false. i.e. Firehose views should be separate
.isFirehose_(false)
.bank_id(null)
.account_id(null)
.name_(StringHelpers.capify(name))
@ -937,8 +937,6 @@ object MapperViews extends Views with MdcLoggable {
.canSeeOtherAccountSWIFT_BIC_(true)
.canSeeOtherAccountIBAN_(true)
.canSeeOtherAccountBankName_(true)
entity
.canSeeOtherAccountNumber_(true)
.canSeeOtherAccountMetadata_(true)
.canSeeOtherAccountKind_(true)
@ -983,6 +981,18 @@ object MapperViews extends Views with MdcLoggable {
.canSeeOtherAccountRoutingAddress_(true)
.canAddTransactionRequestToOwnAccount_(true) //added following two for payments
.canAddTransactionRequestToAnyAccount_(true)
name match {
case SYSTEM_STAGE_ONE_VIEW_ID =>
entity
.canSeeTransactionDescription_(false)
.canAddTransactionRequestToAnyAccount_(false)
case SYSTEM_FIREHOSE_VIEW_ID =>
entity
.isFirehose_(true)
case _ =>
entity
}
}
def unsavedFirehoseView(bankId : BankId, accountId: AccountId, description: String) : ViewDefinition = {

View File

@ -0,0 +1,38 @@
<!--
Open Bank Project - API
Copyright (C) 2011-2017, TESOBE GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Email: contact@tesobe.com
TESOBE GmbH
Osloerstrasse 16/17
Berlin 13359, Germany
This product includes software developed at
TESOBE (http://www.tesobe.com/)
-->
<div id="register-consumer" data-lift="surround?with=default;at=content" tabindex="-1">
<div id="register-consumer-explanation">
<h1><lift:loc locid="already.logged.in.title">Looks like a user is logged in</lift:loc></h1>
<p>
<lift:loc locid="already.logged.in">You must be logged off in order to start user logging process.</lift:loc>
<a class="btn btn-default logout" id="logout_link" data-lift="WebUI.alreadyLoggedIn" href="">
<lift:loc locid="logout">Log off</lift:loc>
</a>
</p>
</div>
</div>

View File

@ -281,11 +281,11 @@ Berlin 13359, Germany
</div>
<div class="col-xs-1" type="hidden"></div>
<div class="main-support-item col-xs-3">
<img class="support-twitter" src="/media/images/icons/support/twitter.svg" width="48" height="48"
<div data-lift="WebUI.socialLink" class="main-support-item col-xs-3">
<img id="footer-social-logo-url" class="support-twitter" src="/media/images/icons/support/twitter.svg" width="48" height="48"
alt="twitter"/>
<h3>Twitter</h3>
<a href="https://twitter.com/openbankproject">@OpenBankProject</a>
<h3 id="footer-social-handle">Twitter</h3>
<a id="footer-social-link" href="https://twitter.com/openbankproject">@OpenBankProject</a>
</div>
<div class="col-xs-1" type="hidden"></div>

View File

@ -45,7 +45,7 @@
<a href="/user_mgt/sign_up" id="authorise-signup" class="btn btn-default pull-right authorise-button" tabindex="0"><lift:loc locid="register">Register</lift:loc></a>
</div>
<div class ="login-or">><lift:loc locid="or_login_with_openid">or Login with OpenID :</lift:loc> </div>
<div class ="login-or"><lift:loc locid="or_login_with_openid"> or Login with OpenID :</lift:loc></div>
<hr>
<div data-lift="OpenIDConnectSnippet.showFirstButton">
<div data-lift="OpenidConnectInvoke.linkButtonFirstProvider">

View File

@ -215,7 +215,7 @@ Berlin 13359, Germany
<lift:loc locid="privacy_policy">Privacy Policy</lift:loc></a>
</li>
<li>
<a href="http://twitter.com/#!/OpenBankProject">Twitter</a>
<a id="footer-div-social" href="http://twitter.com/#!/OpenBankProject" data-lift="WebUI.footerSocialLink">Twitter</a>
</li>
<li>
<a href="https://github.com/OpenBankProject/OBP-API/">Github</a>

View File

@ -182,6 +182,7 @@ class API1_2_1Test extends ServerSetupWithTestData with DefaultUsers with Privat
.filterNot(_.id.contains(SYSTEM_OWNER_VIEW_ID))
.filterNot(_.id.contains(SYSTEM_AUDITOR_VIEW_ID))
.filterNot(_.id.contains(SYSTEM_ACCOUNTANT_VIEW_ID))
.filterNot(_.id.contains(SYSTEM_FIREHOSE_VIEW_ID))
val randomPosition = nextInt(possibleViewsPermalinksWithoutOwner.size)
possibleViewsPermalinksWithoutOwner(randomPosition).id
}

View File

@ -31,7 +31,7 @@ class FirehoseTest extends V300ServerSetup with PropsReset{
setPropsValues("enable.force_error"->"true")
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanUseAccountFirehoseAtAnyBank.toString)
When("We send the request")
val request = (v3_0Request / "banks" / testBankId1.value /"firehose" / "accounts" / "views"/"owner").GET <@ (user1)
val request = (v3_0Request / "banks" / testBankId1.value /"firehose" / "accounts" / "views"/"firehose").GET <@ (user1)
val response = makeGetRequest(request)
Then("We should get a 200 and check the response body")
response.code should equal(200)
@ -41,7 +41,7 @@ class FirehoseTest extends V300ServerSetup with PropsReset{
setPropsValues("allow_firehose_views" -> "true")
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanUseAccountFirehoseAtAnyBank.toString)
When("We send the request")
val request = (v3_0Request / "banks" / testBankId1.value /"firehose" / "accounts" / "views"/"owner").GET <@ (user1)
val request = (v3_0Request / "banks" / testBankId1.value /"firehose" / "accounts" / "views"/"firehose").GET <@ (user1)
val response = makeGetRequest(request)
Then("We should get a 200 and check the response body")
response.code should equal(200)
@ -52,7 +52,7 @@ class FirehoseTest extends V300ServerSetup with PropsReset{
scenario("We will call the endpoint missing role", VersionOfApi, ApiEndpoint2) {
setPropsValues("allow_account_firehose" -> "true")
When("We send the request")
val request = (v3_0Request / "banks" / testBankId1.value / "firehose" / "accounts" / "views" / "owner").GET <@ (user1)
val request = (v3_0Request / "banks" / testBankId1.value / "firehose" / "accounts" / "views" / "firehose").GET <@ (user1)
val response = makeGetRequest(request)
Then("We should get a 403 and check the response body")
response.code should equal(403)
@ -62,7 +62,7 @@ class FirehoseTest extends V300ServerSetup with PropsReset{
scenario("We will call the endpoint missing props ", VersionOfApi, ApiEndpoint2) {
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanUseAccountFirehoseAtAnyBank.toString)
When("We send the request")
val request = (v3_0Request / "banks" / testBankId1.value /"firehose" / "accounts" / "views"/"owner").GET <@ (user1)
val request = (v3_0Request / "banks" / testBankId1.value /"firehose" / "accounts" / "views"/"firehose").GET <@ (user1)
val response = makeGetRequest(request)
Then("We should get a 400 and check the response body")
response.code should equal(400)

View File

@ -415,9 +415,7 @@ class DynamicEntityTest extends V400ServerSetup {
dynamicEntitiesGetJson.values should have size 2
val head= dynamicEntitiesGetJson.arr.head
head should equal(expectUpdatedResponseJson)
dynamicEntitiesGetJson.arr should contain(expectUpdatedResponseJson)
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanDeleteDynamicEntity.toString)
When("We make a request v4.0.0 with the Role " + canDeleteDynamicEntity)
@ -537,9 +535,7 @@ class DynamicEntityTest extends V400ServerSetup {
dynamicEntitiesGetJson.values should have size 2
val head = dynamicEntitiesGetJson.arr.head
head should equal(expectUpdatedResponseJson)
dynamicEntitiesGetJson.arr should contain(expectUpdatedResponseJson)
{
// get a DynamicEntity with wrong user

View File

@ -28,7 +28,7 @@ class FirehoseTest extends V400ServerSetup with PropsReset{
setPropsValues("allow_account_firehose" -> "true")
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanUseAccountFirehoseAtAnyBank.toString)
When("We send the request")
val request = (v4_0_0_Request / "banks" / testBankId1.value /"firehose" / "accounts" / "views"/"owner").GET <@ (user1)
val request = (v4_0_0_Request / "banks" / testBankId1.value /"firehose" / "accounts" / "views"/ "firehose").GET <@ (user1)
val response = makeGetRequest(request)
Then("We should get a 200 and check the response body")
response.code should equal(200)
@ -38,7 +38,7 @@ class FirehoseTest extends V400ServerSetup with PropsReset{
setPropsValues("allow_firehose_views" -> "true")
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanUseAccountFirehoseAtAnyBank.toString)
When("We send the request")
val request = (v4_0_0_Request / "banks" / testBankId1.value /"firehose" / "accounts" / "views"/"owner").GET <@ (user1)
val request = (v4_0_0_Request / "banks" / testBankId1.value /"firehose" / "accounts" / "views"/ "firehose").GET <@ (user1)
val response = makeGetRequest(request)
Then("We should get a 200 and check the response body")
response.code should equal(200)
@ -48,7 +48,7 @@ class FirehoseTest extends V400ServerSetup with PropsReset{
scenario("We will call the endpoint missing role", VersionOfApi, ApiEndpoint1) {
setPropsValues("allow_account_firehose" -> "true")
When("We send the request")
val request = (v4_0_0_Request / "banks" / testBankId1.value / "firehose" / "accounts" / "views" / "owner").GET <@ (user1)
val request = (v4_0_0_Request / "banks" / testBankId1.value / "firehose" / "accounts" / "views" / "firehose").GET <@ (user1)
val response = makeGetRequest(request)
Then("We should get a 403 and check the response body")
response.code should equal(403)
@ -58,7 +58,7 @@ class FirehoseTest extends V400ServerSetup with PropsReset{
scenario("We will call the endpoint missing props ", VersionOfApi, ApiEndpoint1) {
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, ApiRole.CanUseAccountFirehoseAtAnyBank.toString)
When("We send the request")
val request = (v4_0_0_Request / "banks" / testBankId1.value /"firehose" / "accounts" / "views"/"owner").GET <@ (user1)
val request = (v4_0_0_Request / "banks" / testBankId1.value /"firehose" / "accounts" / "views"/ "firehose").GET <@ (user1)
val response = makeGetRequest(request)
Then("We should get a 400 and check the response body")
response.code should equal(400)

View File

@ -1,9 +1,8 @@
package code.setup
import java.util.{Calendar, Date}
import code.accountholders.AccountHolders
import code.api.Constant.{SYSTEM_ACCOUNTANT_VIEW_ID, SYSTEM_AUDITOR_VIEW_ID, SYSTEM_OWNER_VIEW_ID}
import code.api.Constant.{SYSTEM_ACCOUNTANT_VIEW_ID, SYSTEM_AUDITOR_VIEW_ID, SYSTEM_FIREHOSE_VIEW_ID, SYSTEM_OWNER_VIEW_ID}
import code.api.util.{APIUtil, OBPLimit, OBPOffset}
import code.bankconnectors.{Connector, LocalMappedConnector}
import code.model._
@ -72,11 +71,13 @@ trait TestConnectorSetup {
val systemOwnerView = getOrCreateSystemView(SYSTEM_OWNER_VIEW_ID)
val systemAuditorView = getOrCreateSystemView(SYSTEM_AUDITOR_VIEW_ID)
val systemAccountantView = getOrCreateSystemView(SYSTEM_ACCOUNTANT_VIEW_ID)
val systemFirehoseView = getOrCreateSystemView(SYSTEM_FIREHOSE_VIEW_ID)
accounts.foreach(account => {
Views.views.vend.grantAccessToSystemView(account.bankId, account.accountId, systemOwnerView, user)
Views.views.vend.grantAccessToSystemView(account.bankId, account.accountId, systemAuditorView, user)
Views.views.vend.grantAccessToSystemView(account.bankId, account.accountId, systemAccountantView, user)
Views.views.vend.grantAccessToSystemView(account.bankId, account.accountId, systemFirehoseView, user)
val customPublicView = createPublicView(account.bankId, account.accountId)
Views.views.vend.grantAccessToCustomView(customPublicView.uid, user)

View File

@ -1,6 +1,7 @@
package code.util
import code.api.util.PegdownOptions.{convertPegdownToHtmlTweaked,convertHtmlMarkdown}
import code.api.util.PegdownOptions
import code.api.util.PegdownOptions.convertPegdownToHtmlTweaked
import net.liftweb.util.Html5
import org.scalatest.{FlatSpec, Matchers, Tag}
@ -43,193 +44,319 @@ class PegdownOptionsTest extends FlatSpec with Matchers {
val descriptionApiExplorer = stringToNodeSeq(descriptionHtml)
val descriptionApiExplorer2 = stringToNodeSeq(descriptionHtml2)
// println(descriptionHtml)
// println(descriptionHtml2)
val html ="""<h3>
| Description</h3>\\nThe PISP sent a Payment/Transfer Request through a POST command.
|<br>\\n The ASPSP registered the Payment/Transfer Request, updated if necessary the relevant identifiers in order to avoid duplicates and returned the location of the updated Request.
|<br>\\n The PISP got the Payment/Transfer Request that has been updated with the resource identifiers, and eventually the status of the Payment/Transfer Request and the status of the subsequent credit transfer.
|<br>\\n The PISP request for the payment cancellation (global cancellation) or for some payment instructions cancellation (partial cancellation)
|<br>\\n No other modification of the Payment/Transfer Request is allowed.
|<br/>\\n<h3>Prerequisites</h3>\\n
|<ul>\\n
| <li>The TPP was registered by the Registration Authority for the PISP role
| </li>
| \\n
| <li>The TPP was provided with an OAUTH2 \\\"Client Credential\\\" access
| token by the ASPSP (cf. § 3.4.3).
| </li>
| \\n
| <li>The TPP previously posted a Payment/Transfer Request which was saved by
| the ASPSP (cf. § 4.5.3)
| </li>
| \\n
| <ul>\\n
| <li>The ASPSP answered with a location link to the saved
| Payment/Transfer Request (cf. § 4.5.4)
| </li>
| \\n
| <li>The PISP retrieved the saved Payment/Transfer Request (cf. §
| 4.5.4)
| </li>
| \\n
| </ul>
| \\n
| <li>The TPP and the ASPSP successfully processed a mutual check and
| authentication
| </li>
| \\n
| <li>The TPP presented its \\\"OAUTH2 Client Credential\\\" access token.
| </li>
| \\n
| <li>The TPP presented the payment/transfer request.</li>
| \\n
| <li>The PSU was successfully authenticated.</li>
| \\n
|</ul>\\n<h3>Business flow</h3>\\nthe following cases can be applied:\\n
|<ul>\\n
| <li>Case of a payment with multiple instructions or a standing order, the
| PISP asks to cancel the whole Payment/Transfer or Standing Order Request
| including all non-executed payment instructions by setting the
| [paymentInformationStatus] to \\\"RJCT\\\" and the relevant
| [statusReasonInformation] to \\\"DS02\\\" at payment level.
| </li>
| \\n
| <li>Case of a payment with multiple instructions, the PISP asks to cancel
| one or several payment instructions by setting the [transactionStatus]
| to \\\"RJCT\\\" and the relevant [statusReasonInformation] to
| \\\"DS02\\\" at each relevant instruction level.
| </li>
| \\n
|</ul>\\nSince the modification request needs a PSU authentication before committing, the modification request includes:</li>\\n
|<ul>\\n
| <li>The specification of the authentication approaches that are supported by
| the PISP (any combination of \\\"REDIRECT\\\", \\\"EMBEDDED\\\" and
| \\\"DECOUPLED\\\" values).
| </li>
| \\n
| <li>In case of possible REDIRECT or DECOUPLED authentication approach, one
| or two call-back URLs to be used by the ASPSP at the finalisation of the
| authentication and consent process :
| </li>
| \\n
| <ul>\\n
| <li>The first call-back URL will be called by the ASPSP if the Transfer
| Request is processed without any error or rejection by the PSU
| </li>
| \\n
| <li>The second call-back URL is to be used by the ASPSP in case of
| processing error or rejection by the PSU. Since this second URL is
| optional, the PISP might not provide it. In this case, the ASPSP
| will use the same URL for any processing result.
| </li>
| \\n
| <li>Both call-back URLS must be used in a TLS-secured request.</li>
| \\n
| </ul>
| \\n
| <li>In case of possible \\\"EMBEDDED\\\" or \\\"DECOUPLED\\\" approaches, a
| PSU identifier that can be processed by the ASPSP for PSU recognition.
| </li>
| \\n
|</ul>\\n
|<li>The ASPSP saves the updated Payment/Transfer Request and answers to the
| PISP. The answer embeds
|</li>\\n
|<ul>\\n
| <li>The specification of the chosen authentication approach taking into
| account both the PISP and the PSU capabilities.
| </li>
| \\n
| <li>In case of chosen REDIRECT authentication approach, the URL to be used
| by the PISP for redirecting the PSU in order to perform an
| authentication.
| </li>
| \\n
|</ul>\\n</ul>\\n<h3>Authentication flows for both use cases</h3>\\n<h4>Redirect
| authentication
| approach </h4>\\nWhen the chosen authentication approach within the ASPSP answers is set to \\\"REDIRECT\\\":
|<br>\\n
|<ul>\\n
| <li>The PISP redirects the PSU to the ASPSP which authenticates the PSU</li>
| \\n
| <li>The ASPSP asks the PSU to give (or deny) his/her consent to the Payment
| Request global or partial Cancellation
| </li>
| \\n
| <li>The ASPSP is then able to initiate the subsequent cancellation</li>
| \\n
| <li>The ASPSP redirects the PSU to the PISP using one of the call-back URLs
| provided within the posted Payment Request cancellation
| </li>
| \\n
|</ul>\\nIf the PSU neither gives nor denies his/her consent, the Cancellation Request shall expire and is then rejected to the PISP. The expiration delay is specified by each ASPSP.
|<br>\\n<h4>Decoupled authentication
| approach</h4>\\nWhen the chosen authentication approach is \\\"DECOUPLED\\\":
|<br>\\n
|<ul>\\n
| <li>Based on the PSU identifier provided within the Payment Request by the
| PISP, the ASPSP provides the PSU with the Cancellation Request details
| and challenges the PSU for a Strong Customer Authentication on a
| decoupled device or application.
| </li>
| \\n
| <li>The PSU confirms or not the Payment Request global or partial
| Cancellation
| </li>
| \\n
| <li>The ASPSP is then able to initiate the subsequent cancellation</li>
| \\n
| <li>The ASPSP notifies the PISP about the finalisation of the authentication
| and cancellation process by using one of the call-back URLs provided
| within the posted Payment Request
| </li>
| \\n
|</ul>\\nIf the PSU neither gives nor denies his/her consent, the Cancellation Request shall expire and is then rejected to the PISP. The expiration delay is specified by each ASPSP.
|<br>\\n<h4>Embedded authentication
| approach</h4>\\nWhen the chosen authentication approach within the ASPSP answers is set to \\\"EMBEDDED\\\":
|<br>\\n
|<ul>\\n
| <li>The TPP informs the PSU that a challenge is needed for completing the
| Payment Request cancellation processing. This challenge will be one of
| the following:
| </li>
| \\n
| <ul>\\n
| <li>A One-Time-Password sent by the ASPSP to the PSU on a separate
| device or application.
| </li>
| \\n
| <li>A response computed by a specific device on base of a challenge sent
| by the ASPSP to the PSU on a separate device or application.
| </li>
| \\n
| </ul>
| \\n
| <li>The PSU unlock the device or application through a \\\"knowledge
| factor\\\" and/or an \\\"inherence factor\\\" (biometric), retrieves the
| cancellation details.
| </li>
| \\n
| <li>The PSU confirms or not the Payment Request global or partial
| Cancellation
| </li>
| \\n
| <li>When agreeing the Payment Request cancellation, the PSU enters the
| resulting authentication factor through the PISP interface which will
| forward it to the ASPSP through a confirmation request (cf. § 4.7)
| </li>
| \\n
|</ul>\\nCase of the PSU neither gives nor denies his/her consent, the Cancellation Request shall expire and is then rejected to the PISP. The expiration delay is specified by each ASPSP.
|<br>""".stripMargin
// this response still contains `\[` there, need to be fixed.
val markdown = convertHtmlMarkdown(html)
// println(markdown)
stringToNodeSeq(markdown)
val markdownText ="""Privacy policy
|====================
|
|Privacy policy
|====================
|
|Learn more about our website
|
|On this page
|
|* [About this site](#Top)
|* [Definitions](#Definitions)
|* [Access and licenses](#Access)
|* [Intellectual property rights](#Intellectual-property)
|* [Prohibitions on use](#Prohibitions)
|* [No warranties](#warranties)
|* [Suspension](#Suspension)
|* [Liability and Indemnities](#Liability)
|* [General](#General)
|* [Contact details](#Contact)
|* [Appendix](#Appendix)
|
|* * *
|
|About this Site
|---------------
|
|The Site is provided by ABCD Bank Plc (**ABCD**, **we** and **us**) and provides documentation for certain Testing Facilities and various ABCD Group APIs.
|
|ABCD Bank plc is authorised by the Prudential Regulation Authority and regulated by the Financial Conduct Authority and the Prudential Regulation Authority. It is listed with the registration number 114216. ABCD Bank Plc is a company incorporated under the laws of England and Wales with company registration number 14259 and its registered office at 8 Canada Square, ABCD Bank Plcs registered VAT number is GB 365684514.
|
|This document sets out the terms and conditions ("**Terms**") of this Site. These Terms govern your use of this Site together with the provision and use of any interface or data obtained through on or accessed via this Site including the APIs.
|
|By accessing this Site, you agree to be bound by these Terms so please read these Terms carefully. The [Privacy Notice](/privacy-notice "Privacy notice") and [Cookie Notice](/cookie-notice "Cookie notice") explain how we collect, use and share your personal information and what information we store on or read from the device you use to access this Site. We may change the content or services found on this Site at any time without notice, and / or these Terms, the Cookies Notice or the Privacy Notice at any time without notice. You should visit this page regularly to check for any changes, and by continuing to use this Site you are agreeing to any changes to these Terms. These Terms were last amended on 29th March 2021.
|
|We will not charge you for access to this Site and we do not guarantee that the Site, or any content on it, will always be available or uninterrupted. We may suspend or restrict access to the Site or any part of it for business, regulatory or operational purposes. We will endeavour to give reasonable notice of any suspension .
|
|**If you do not agree with these Terms, any relevant Licence Terms, the Privacy Notice or our use of cookies as set out in the Cookies Notice, please do not use this Site or the APIs.**
|
|* * *
|
|Definitions
|-----------
|
|1. **APIs** means the API provided by ABCD Group and made available on the Site. For the avoidance of doubt APIs does not include any third party APIs which may be offered through this Site.
|2. **API Documentation** means any information, guidance, specifications or other documentation and information provided via this Site or otherwise to you about the APIs, this Site or the Testing Facilities.
|3. **Developer** means a third party who provides technology services to you: (i) to enable you to access and use any element of the APIs or Testing Facilities; (ii) to support your API Testing and / or (iii) to facilitate your integration of and / or to maintain the integration of any of the APIs into your application.
|4. **ABCD** means ABCD UK Bank plc, and references to "we", "us" or "our" are references to ABCD and / or the ABCD Group, as applicable.
|5. **API Terms** means any terms and conditions that apply to your use of any API, or to the integration of any API with a system or service.
|6. **API Testing** means your (or a Developer acting on your behalfs) testing of any application developed or used by you, or developed on your behalf, for the purposes of enabling your access to, benefit from, reliance on and / or interaction or integration with the APIs;
|7. **ABCD Group** ABCD Holdings plc, its subsidiaries, related bodies corporate, associated entities and undertakings and any of their branches. full details of all relevant members are available at Appendix 1.
|8. **Intellectual Property Rights** means any right, title or interest in: copyrights, rights in databases, patents, inventions, patents, trademarks, trade names, goodwill, rights in internet domain names and website addresses, designs, know how, trade secrets and other rights in confidential information, whether registered, unregistered or not capable of being registered in any country or jurisdiction including all other rights having equivalent or similar affects which may now or in the future subsist anywhere in the world.
|9. **Licence Terms** means any licence applying to the use of any third party APIs (other than those provided by ABCD available on this Site) including but not limited to the Open Banking Open Licence (available: [https://www.openbanking.org.uk/wp-content/uploads/Open-Licence.pdf](https://www.openbanking.org.uk/wp-content/uploads/Open-Licence.pdf)).
|10. **Site** means https://develop.ABCD.com.
|11. **Site Account** means any user account created on this Site.
|12. **Terms** means these Terms and Conditions.
|13. **Testing Documentation** means any information, guidance, specifications or other documentation and information provided via this Site about the Testing Facilities.
|14. Testing Facilities means one or more testing environments, activities, or sandboxes that we provide or make available to you on this Site to: (i) access the API Documentation; and / or (ii) enable you to carry out API Testing.
|15. **You or you** means the person accessing this Site or using the APIs available via this Site.
|
|* * *
|
|Access and licenses
|-------------------
|
|1. In consideration of your compliance with the Terms, we grant you a non-exclusive, royalty free, revocable, non-transferable and non-sub licensable licence to access and use the Site, the Testing Facilities and the Testing Documentation.
|2. Access to certain restricted parts of the Site, the Testing Facilities, the Testing Documentation, the API Documentation and the APIs may be granted at our absolute discretion (or that of another member of the ABCD Group) and/or your satisfaction of regulatory requirements. Where such access is granted, it may be subject to your creation of a Site Account, your agreement to further terms or other obligations as we may require and may be withdrawn at any time without notice or liability (to the extent permissible by applicable law).
|3. Your use of any third party APIs are subject to any relevant API Terms and any Additional Licence Terms. You are responsible for your access to the Site, use of the Testing Facilities and Testing Documentation and for all activities that occur whilst you are logged into your Site Account. If you know or suspect that anyone other than you knows your Site Account user name or password or any details relating to your organisation that might allow your Site Account to be used by others, you must notify us immediately by using the Support form found under the Resources menu.
|4. Your use of any third party links contained on this Site is at your own risk. We are not responsible for the content of any other web sites or pages linked to or from this Site and have not verified the content of any such web sites, or pages.
|5. You must ensure compliance with all applicable law in connection with your use of this Site, the Testing Facilities, the Testing Documentation, the API Documentation and the APIs.
|
|* * *
|
|Intellectual property rights
|----------------------------
|
|1. We or other members of the ABCD Group are the owner or licensee of all Intellectual Property Rights subsisting in the APIs, API Documentation, the Testing Facilities, the Testing Documentation and this Site. All rights in and to the APIs, the API Documentation, the Testing Facilities, the Testing Documentation and this Site are reserved.
|2. You acknowledge that we are the owner or the licensee of all Intellectual Property Rights in material published on this Site (including for the avoidance of doubt any user-generated information and comments posted by third parties on the Site). All such rights are reserved.
|3. You may print off one copy, and may download extracts, of any page(s) from this Site for your own use.
|4. Nothing in these Terms shall be construed as granting any rights for you to use any ABCD logos, trademarks or branding.
|
|* * *
|
|Prohibitions on use
|-------------------
|
|Except as may be permitted under applicable law, you must not use the APIs, API Documentation, the Testing Facilities, the Testing Documentation or this Site:
|
|1. for any purpose which is unlawful, abusive, libelous, obscene or threatening;
|2. except to the extent expressly permitted under these Terms and under any API Terms, attempt to adapt, copy, modify, download, display, duplicate, create derivative works from, republish, transmit, or distribute all or any portion of the APIs, API Documentation, the Testing Facilities, the Testing Documentation or this Site.
|3. either in whole or part, attempt to reverse engineer, decompile, disassemble or otherwise reduce to human-perceivable form all or any part of the APIs, the Testing Facilities or this Site;
|4. for purposes of misuse by knowingly or unknowingly introducing viruses, trojans, worms, logic bombs or other material which is malicious or technologically harmful;
|5. for any purpose that could, or could potentially infringe the Intellectual Property Rights, privacy, confidentiality or other rights of any third party; or
|6. for any other purpose other than that for which your access was granted.
|
|* * *
|
|No warranties
|-------------
|
|To the fullest extent permitted by law, and unless expressly set out to the contrary in these Terms:
|
|1. all warranties and terms which would otherwise be implied by law, custom or usage are excluded from these Terms;
|2. all access to this Site and (where you have been granted access) to the APIs and the Testing Facilities is made available to you on an "as is" and "as available" basis. We may suspend your access to, suspend, withdraw, discontinue or change, all or any of the Site, your Site Account, the Testing Facilities, the Testing Documentation, the API Documentation or the APIs at any time without notice or liability;
|3. we make no representations, warranties or guarantees, whether express or implied that this Site, the Testing Facilities, the Testing Documentation, the API Documentation or the APIs (including any data obtained through the APIs) is accurate, complete or up-to-date although we do use reasonable care to ensure that this Site, the Testing Facilities, the Testing Documentation, the API Documentation and the APIs are accurate in so far as this is within our control.
|4. We do not guarantee that our Site will be secure or free from bugs or viruses, you are responsible for configuring and securing your own information technology, computer programmes, platforms and equipment and should use your own virus protection software.
|
|* * *
|
|Suspension
|----------
|
|We may suspend your access to the Site, your Site Account, or terminate these Terms at any time if in our sole discretion:
|
|1. you are in breach of any of the terms and conditions of these Terms;
|2. you or your Site Account suffer a security breach that impacts on the confidentiality or integrity of this Site; or
|3. we have a legitimate concern about your use of this Site or your Site Account.
|
|* * *
|
|Liability and Indemnities
|-------------------------
|
|1. Nothing in these Terms excludes or limits our liability for death or personal injury arising from our negligence, or our fraud or fraudulent misrepresentation, or any other liability that cannot be excluded or limited by law.
|2. To the full extent permitted by law, in no event will we, any other member of the ABCD Group, or any third party API providers be liable to you for any loss or damage (whether direct or indirect), whether in contract, tort (including negligence), breach of statutory duty, or otherwise, even if foreseeable, arising under or in connection with:
| 1. your use, or inability to use this Site, your Site Account, the Testing Facilities, the Testing Documentation, the API Documentation or the APIs; or
| 2. your use of or reliance on any content accessed through this Site or the APIs.
|3. Notwithstanding the remainder of this Clause 8, the total aggregate liability of the ABCD Group, whether in contract, tort (including negligence and breach of statutory duty, howsoever arising), misrepresentation (whether negligent or innocent), restitution or otherwise, arising under or in connection with these Terms shall be limited to £500 in aggregate.
|
|* * *
|
|General
|-------
|
|1. **Relationship**: Nothing in, and no action taken under, these Terms creates a relationship of principal and agent between you and ABCD or any other ABCD Group member, or otherwise authorises you to bind ABCD or any other ABCD Group member.
|2. **Third Party Rights**: A person who is not party to these Terms of Use may not enforce any term of these Terms under the Contracts (Rights of Third Parties) Act 1999.
|3. **Assignment**: you may not assign, transfer or permit the exercise by any other party of your rights under these Terms. We may subcontract, assign or novate these Terms or any of our rights to any member of the ABCD Group or third party.
|4. **Entire Agreement**: These Terms, together with the documents referred to in it, constitutes the entire agreement and understanding between the parties in respect of the matters dealt with in it and supersedes any previous agreement between the parties in relation to such matters.
|5. **Governing Law and Jurisdiction**: The Terms are governed by and interpreted in accordance with the laws of England and Wales and the courts of the above jurisdiction will have exclusive jurisdiction in respect of any dispute, which may arise.
|
|* * *
|
|Contact Details
|---------------
|
|If you have any questions in respect of these terms, please send us a message using the Support form found under the Resources menu or contact your Integration Manager (Corporate customers).
|
|
|[Return to top](#Top)
|
|* * *
|
|Appendix
|--------
|
|Jurisdiction
|
|Legal entity
|
|Full details
|
|UK
|
|ABCD UK Bank plc
|
|
|ABCD Bank plc
|
|
|Marks & Spencer Financial Services plc
|
|ABCD UK Bank plc is authorised by the Prudential Regulation Authority and regulated by the Financial Conduct Authority and the Prudential Regulation Authority. It is listed with the registration number 765112. ABCD UK Bank plc is a company incorporated under the laws of England and wales with company registration number 9928412 and its registered office at 1 Centenary Square, Birmingham, B1 1HQ. ABCD UK Bank plcs registered VAT number is GB 365684514. first direct is a division of ABCD UK Bank plc
|
|ABCD Bank plc is authorised by the Prudential Regulation Authority and regulated by the Financial Conduct Authority and the Prudential Regulation Authority. It is listed with the registration number 114216. ABCD Bank plc is a company incorporated under the laws of England and Wales with company registration number 14259 and its registered office at 8 Canada Square, London E14 5HQ. ABCD Bank plcs registered VAT number is GB 365684514
|
|M&S Bank is a trading name of Marks & Spencer Financial Services plc. Registered in England No. 1772585. Registered Office: Kings Meadow, Chester, CH99 9FB. Authorised by the Prudential Regulation Authority and regulated by the Financial Conduct Authority and the Prudential Regulation Authority. Marks & Spencer Financial Services plc is entered in the Financial Services Register under reference number 151427. M&S Bank is part of the ABCD Group. Marks & Spencer is a registered trademark of Marks and Spencer plc and is used under licence. © Marks & Spencer Financial Services plc 2018. All rights reserved
|
|Germany
|
|ABCD Trinkaus & Burkhardt AG
|
|Regulatory authority:
|
|German Federal Financial Supervisory Authority (Bundesanstalt für Finanzdienstleistungsaufsicht), Graurheindorfer Str. 108, 53117 Bonn, Germany and Marie-Curie-Straße 24-28, 60439 Frankfurt am Main, Germany
|
|European Central Bank, Sonnemannstraße 20, 60314 Frankfurt am Main, Germany
|
|Commercial Register entries:
|
|Dusseldorf District Court, commercial register no. HRB 54447
|
|VAT ID No.:
|
|DE 121310482
|
|BIC: TUBDDEDDXXX
|
|LEI: JUNT405OW8OY5GN4DX16
|
|
|France
|
|ABCD Continental Europe (previously ABCD France)
|
|ABCD Continental Europe is supervised by the European Central Bank (ECB), as part of the Single Supervisory Mechanism (SSM), the French Prudential Supervisory and Resolution Authority (lAutorité de Contrôle Prudentiel et de Résolution 4, place de Budapest, CS 92459, 75436 Paris Cedex 09, France) (ACPR) as the French National Competent Authority and the French Financial Markets Authority (lAutorité des Marchés Financiers (AMF) for the activities carried out over financial instruments or in financial markets. Further, ABCD France is registered as an insurance broker with the French Organisation for the Registration of financial intermediaries (Organisme pour le Registre unique des Intermédiaires en Assurance, banque et finance www.orias.fr) under nr.07005894.
|
|Czech Republic
|
|ABCD Continental Europe, pobočka Praha
|
|ABCD Continental Europe a company incorporated under the laws of France as a société anonyme (registered number 775 670 284 RCS Paris), having its registered office at 103, avenue des Champs-Elysées, 75008 Paris, France, is authorised as a credit institution and investment services provider by the Autorité de Contrôle Prudentiel et de Résolution (ACPR), regulated by the Autorité des Marchés Financiers (AMF) and the ACPR and controlled by the European Central Bank and is lawfully established in the Czech Republic through a branch ABCD France - pobočka Praha with its registered office at Na Florenci 2116/15, Nové Město, 110 00 Praha, the Czech Republic, identification number 07482728, registered in the Commercial Register kept by the Municipal Court in Prague, Section A, Insert 78901.
|
|Mexico
|
|ABCD Mexico plc., Multiple Banking Institution Financial Group ABCD
|
|ABCD México, S.A., Institución de Banca
|Múltiple, Grupo Financiero ABCD, having its registered office at en Paseo de la Reforma No.347,
|Col. Cuauhtémoc, C.P. 06500, México D.F.
|
|Malta
|
|ABCD Bank Malta plc
|
|ABCD Bank Malta p.l.c. (ABCD Bank) having registration number C 3177 and its registered office at 116, Archbishop Street, Valletta, VLT 1444, Malta.
|
|Greece
|
|ABCD Continental Europe, Athens Branch
|
|ABCD Continental Europe is lawfully established in Greece as a branch, duly registered with the General Commercial Registry (GEMI), with registered office at 109-111 Messoghion Ave., Athens. ABCD Continental Europe, Athens branch is authorized by the ECB, the ACPR and the Bank of Greece; its banking activities in Greece are further subject to limited supervision by the Bank of Greece (21 Eleftheriou Venizelou, Athens) and the Hellenic Capital Market Commission (1 Kolokotroni, Athens) exclusively with regard to the issues provided for by the applicable legislation.
|
|Ireland
|
|ABCD Continental Europe, Dublin Branch
|
|ABCD Continental Europe, Dublin Branch which is a registered business name of ABCD Continental Europe, a branch registered in Ireland (registration number 908966) having its registered office at 1 Grand Canal Square, Grand Canal Harbour, Dublin 2, D02 P820 and regulated by the Central Bank of Ireland for conduct of business rules.
|
|Poland
|
|ABCD Continental Europe (Spółka Akcyjna) Oddział w Polsce
|
|ABCD Continental Europe (Spółka Akcyjna) Oddział w Polsce, with its seat in Warsaw, at Rondo ONZ 1, 00-124 Warsaw, and registered in the register of entrepreneurs of the National Court Register maintained by the District Court in Warsaw, XII Commercial Department of the National Court Register under KRS No. 0000757904, with a tax identification number NIP 107-00-41-832, the branch of ABCD Continental Europe, a French société anonyme with a share capital of EUR 428368915, fully paid up, whose corporate seat is 103 Avenue des Champs Elysées, 75008 Paris, registered with the Trade and Companies Registry of Paris (Registre du Commerce et des Societas) under number 775 670 284, with a Polish NIP number 107-00-41-803
|
|
|Italy
|
|ABCD Continental Europe, Milan Branch
|
|ABCD Continental Europe is authorised as a credit institution and investment services provider by the Autorité de Contrôle Prudentiel et de Résolution (ACPR), regulated by the Autorité des Marchés Financiers (AMF) and the ACPR and controlled by the European Central Bank and is lawfully established in Italy through a branch with its registered office at Via Mike Bongiorno 13, 20124 Milan, registered at the Italian Chamber of Commerce under number 10470920967.
|
|Belgium
|
|ABCD Continental Europe, Brussels Branch
|
|ABCD Continental Europe, Brussels Branch is a branch of ABCD Continental Europe.
|
|ABCD France is incorporated under the laws of France as a société anonyme (SIREN number 775 670 284 RCS Paris), having its registered office at 103, avenue des Champs-Elysées, 75008 Paris, France
|
|ABCD France, Brussels Branch is located Square de Meeûs 23, 1000 Brussels with registered number 0708.865.310.
|
|
|Netherlands
|
|ABCD Continental Europe, Amsterdam Branch
|
|ABCD Continental Europe, Amsterdam Branch is located De Entree 236, 1101 EE Amsterdam Z.O., the Netherlands, and is registered in the Trade Register of the Amsterdam Chamber of Commerce under number 000040776689.
|
|ABCD Continental Europe, Amsterdam Branch is a branch of ABCD Continental Europe.
|
|ABCD Continental Europe is incorporated under the laws of France as a société anonyme (SIREN number 775 670 284 RCS Paris), having its registered office at 103, avenue des Champs-Elysées, 75008 Paris, France.
|
|
|Spain
|
|ABCD Continental Europe, Sucursal en España
|
|ABCD Continental Europe, Sucursal en España, Spanish Tax ID number: W-2502598-B. Number of Register in Bank of Spain (Branches of Foreign EU Credit Entities Register) under the number 0162), with registered address at Torre Picasso, Planta 33, Pza. Pablo Ruiz Picasso, 1 - 28020 Madrid. Registered in the Mercantile Registry of Madrid under the codes T.38.314, Secc. 8 (L.Sociedades), F.1, M-681702, Ins, 1ª. and supervised by the Bank of Spain and the National Securities Market Commission (CNMV).
|
|ABCD Continental Europe, Sucursal en España is a full branch of ABCD France, S.A. - SIREN number 775 670 284 and based in 103, avenue des Champs-Elysées, 75008 Paris, (France) and is supervised by the European Central Bank (ECB) and regulated by the Autorité de Contrôle Prudentiel et de Résolution (ACPR) and the Autorité des Marchés Financiers (AMF).
|
|
|CIIOM
|
|ABCD Bank plc Jersey Branch
|
|ABCD Bank plc Guernsey Branch
|
|Isle of Man ABCD Bank plc
|
|
|ABCD Bank plc Jersey Branch is regulated by the Jersey Financial Services Commission for Banking, General Insurance Mediation and Investment Business.
|
|ABCD Bank plc Guernsey Branch is licensed by the Guernsey Financial Services Commission for Banking, Insurance and Investment Business.
|
|In the Isle of Man ABCD Bank plc is licensed by the Isle of Man Financial Services Authority.
|
|
|Luxembourg
|
|ABCD Private Bank (Luxembourg) S.A.
|
|ABCD Private Bank (Luxembourg) S.A., having its address at 16, Boulevard dAvranches, L-1160 Luxembourg, Luxembourg.
|
|Bahrain
|
|ABCD Bank Middle East Limited Bahrain Branch
|
|ABCD Bank Middle East Limited Bahrain Branch, P.O. Box 57, Manama, Kingdom of Bahrain, licensed and regulated by the Central Bank of Bahrain as a Conventional Retail Bank for the purpose of this promotion and lead regulated by the Dubai Financial Services Authority.
|
|[Return to top](#Top)""".stripMargin
val html = PegdownOptions.convertGitHubDocMarkdownToHtml(markdownText)
}
"description string" should "test the markdown * -> html <li> tag" taggedAs FunctionsTag in {
@ -333,9 +460,4 @@ Authentication is Mandatory""".stripMargin
descriptionHtml3 contains("<p>Authentication is Mandatory</p>") should be (true)
}
}

View File

@ -59,13 +59,17 @@
<artifactId>transmittable-thread-local</artifactId>
<version>2.11.5</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-text -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
@ -76,6 +80,30 @@
<build>
<plugins>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>7.1.1</version>
<configuration>
<name>notifier-dependency-check</name>
<format>HTML</format>
<failBuildOnCVSS>10</failBuildOnCVSS>
<failOnError>false</failOnError>
<skipProvidedScope>true</skipProvidedScope>
<!--skip artifacts not bundled in distribution (Provided and Runtime scope).-->
<skipRuntimeScope>true</skipRuntimeScope>
<skipTestScope>true</skipTestScope>
<retireJsAnalyzerEnabled>false</retireJsAnalyzerEnabled>
<skipArtifactType>pom</skipArtifactType>
</configuration>
<executions>
<execution>
<goals>
<goal>aggregate</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
@ -136,6 +164,7 @@
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

16
pom.xml
View File

@ -12,7 +12,7 @@
<properties>
<scala.version>2.12</scala.version>
<scala.compiler>2.12.10</scala.compiler>
<akka.version>2.5.31</akka.version>
<akka.version>2.5.32</akka.version>
<akka-streams-kafka.version>2.0.5</akka-streams-kafka.version>
<kafka.version>1.1.0</kafka.version>
<avro.version>1.8.2</avro.version>
@ -96,15 +96,17 @@
<artifactId>lift-mapper_${scala.version}</artifactId>
<version>${lift.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.10</version>
<version>3.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-text -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.scalatest</groupId>