Skip to content

Commit

Permalink
Initial commit in new repository.
Browse files Browse the repository at this point in the history
  • Loading branch information
katsumag committed Apr 28, 2024
0 parents commit c7984de
Show file tree
Hide file tree
Showing 55 changed files with 1,391 additions and 0 deletions.
66 changes: 66 additions & 0 deletions .github/workflows/build-containers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Build Containers

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
workflow_dispatch:

permissions:
contents: read

jobs:
build:

runs-on: ubuntu-latest

steps:
- name: Clone source code
uses: actions/checkout@v3
with:
ref: 'main'
submodules: true
token: ${{ secrets.GH_PAT }}

- name: Log in to Docker Registry
uses: docker/login-action@v2
with:
registry: ${{ secrets.DOCKER_REGISTRY_URL }}
username: ${{ secrets.DOCKER_REGISTRY_USERNAME }}
password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }}

- name: Set up JDK 19
uses: actions/setup-java@v3
with:
java-version: '19'
distribution: 'temurin'

- name: Set up Gradle
uses: gradle/gradle-build-action@v2

- name: Build discovery container
run: ./gradlew :discovery:bootBuildImage --imageName=discovery:latest

- name: Build gateway container
run: ./gradlew :gateway:bootBuildImage --imageName=gateway:latest

- name: Build core container
run: ./gradlew :core:bootBuildImage --imageName=core:latest

- name: Build url shortener container
run: ./gradlew :url-shortener:bootBuildImage --imageName=url-shortener:latest

- name: Push containers to Docker Registry
run: |
docker tag discovery:latest ${{ secrets.DOCKER_REGISTRY_URL }}/osable/discovery:latest
docker push ${{ secrets.DOCKER_REGISTRY_URL }}/osable/discovery:latest
docker tag gateway:latest ${{ secrets.DOCKER_REGISTRY_URL }}/osable/gateway:latest
docker push ${{ secrets.DOCKER_REGISTRY_URL }}/osable/gateway:latest
docker tag core:latest ${{ secrets.DOCKER_REGISTRY_URL }}/osable/core:latest
docker push ${{ secrets.DOCKER_REGISTRY_URL }}/osable/core:latest
docker tag url-shortener:latest ${{ secrets.DOCKER_REGISTRY_URL }}/osable/url-shortener:latest
docker push ${{ secrets.DOCKER_REGISTRY_URL }}/osable/url-shortener:latest
26 changes: 26 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Ignore .gradle, gradle, .idea and build directories
/.gradle/
/gradle/
/.idea/
/build/

/build-logic/.gradle/
/build-logic/build/

/core/.gradle/
/core/build/

/gateway/.gradle/
/gateway/build/

/discovery/build/
/discovery/.gradle/

/url-shortener/build/
/url-shortener/.gradle/

# Avoid leaking secrets, please
secrets.yaml

# Don't include any local test blogs
/blogs/
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "core/src/main/resources/frontend"]
path = core/src/main/resources/frontend
url = https://github.com/osable/frontend.git
7 changes: 7 additions & 0 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugins {
`kotlin-dsl`
}

repositories {
gradlePluginPortal()
}
13 changes: 13 additions & 0 deletions build-logic/src/main/kotlin/default-module-config.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
plugins {
kotlin("jvm")
java
id("application")
}

group = "net.osable"
version = "1.0-SNAPSHOT"

repositories {
mavenCentral()
gradlePluginPortal()
}
Empty file.
40 changes: 40 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import org.jetbrains.kotlin.gradle.plugin.extraProperties

plugins {
kotlin("jvm") version "1.7.22"
java
id("org.springframework.boot") version "3.0.3"
id("io.spring.dependency-management") version "1.1.0"
kotlin("plugin.spring") version "1.7.22"
}

group = "net.osable"
version = "1.0-SNAPSHOT"

repositories {
mavenCentral()
}

dependencies {
implementation(kotlin("stdlib"))

// Ktor server
implementation("io.ktor:ktor-server-core-jvm:2.2.1")
implementation("io.ktor:ktor-server-netty-jvm:2.2.1")
implementation("io.ktor:ktor-server-content-negotiation:2.2.1")

//Ktor client
implementation("io.ktor:ktor-client-core:2.2.1")
implementation("io.ktor:ktor-client-cio:2.2.1")
implementation("io.ktor:ktor-client-content-negotiation:2.2.1")

// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")

testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}

tasks.getByName<Test>("test") {
useJUnitPlatform()
}
50 changes: 50 additions & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
plugins {
id("default-module-config")
id("org.springframework.boot") version "3.0.3"
id("io.spring.dependency-management") version "1.1.0"
kotlin("plugin.spring") version "1.7.22"
}

java.sourceCompatibility = JavaVersion.VERSION_17
extra["springCloudVersion"] = "2022.0.1"

dependencies {
implementation("org.springframework.boot:spring-boot-starter")

// Spring MVC
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")

implementation("org.springframework.boot:spring-boot-starter-webflux")

// Metrics
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("io.micrometer:micrometer-registry-prometheus")

// Eureka Discovery
implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")

// Production Cache - replaces default in-memory Spring cache
implementation("org.springframework.boot:spring-boot-starter-cache")
implementation("com.github.ben-manes.caffeine:caffeine:3.1.5")

// Flexmark Markdown -> HTML
implementation("com.vladsch.flexmark:flexmark-all:0.64.0")

testImplementation("org.springframework.boot:spring-boot-starter-test")
}

// handle spring cloud dependency versions
dependencyManagement {
imports {
mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("springCloudVersion")}")
}
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "11"
}
}
16 changes: 16 additions & 0 deletions core/src/main/kotlin/net/osable/core/CaffeineConfiguration.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package net.osable.core

import com.github.benmanes.caffeine.cache.Caffeine
import org.springframework.cache.caffeine.CaffeineCacheManager
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.util.concurrent.TimeUnit

@Configuration
class CaffeineConfiguration {

@Bean fun caffeineConfig() = Caffeine.newBuilder().expireAfterWrite(60, TimeUnit.MINUTES)

@Bean fun cacheManager(caffeine: Caffeine<Any, Any>) = CaffeineCacheManager("blog").apply { setCaffeine(caffeine) }

}
9 changes: 9 additions & 0 deletions core/src/main/kotlin/net/osable/core/CoreApplication.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package net.osable.core

import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication

fun main(args: Array<String>) { SpringApplication.run(CoreApplication::class.java, *args) }

@SpringBootApplication
class CoreApplication
11 changes: 11 additions & 0 deletions core/src/main/kotlin/net/osable/core/Error.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package net.osable.core

import jakarta.servlet.RequestDispatcher
import jakarta.servlet.http.HttpServletRequest
import org.springframework.http.HttpStatus

data class Error(val code: Int, val info: String)

fun HttpServletRequest.getErrorCode() = getAttribute(RequestDispatcher.ERROR_STATUS_CODE) as Int

fun getHttpStatusMessage(code: Int) = HttpStatus.valueOf(code).reasonPhrase
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package net.osable.core

import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal
import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal
import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector
import reactor.core.publisher.Mono

class GitHubReactiveOpaqueTokenIntrospector : ReactiveOpaqueTokenIntrospector {
override fun introspect(token: String): Mono<OAuth2AuthenticatedPrincipal> {
println("Token: $token")
return Mono.just(DefaultOAuth2AuthenticatedPrincipal(mapOf(), null))
}

}
36 changes: 36 additions & 0 deletions core/src/main/kotlin/net/osable/core/RouteMetrics.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package net.osable.core

import io.micrometer.core.instrument.Statistic
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.actuate.metrics.MetricsEndpoint
import org.springframework.stereotype.Component

enum class RouteMetrics(private val endpoint: String, val displayName: String) {

HOME("/", "Homepage"),
ADMIN("/admin", "Admin Panel"),
PRIVACY("/privacy", "Privacy Policy"),
TOOL("/tool", "Tool"),
SECURITY("/security", "Security Policy"),
OPEN_SOURCE("/open-source", "Open Source"),
ABOUT_US("/about-us", "About Us"),
ABOUT_SERPENTINE("/about/serpentine", "About Serpentine");

companion object {
fun getTotalRequests(metricsEndpoint: MetricsEndpoint) = values().sumOf { it.getRequestsToURL(metricsEndpoint) }
fun getRequestsPerRoute(metricsEndpoint: MetricsEndpoint) = mutableMapOf<String, Int>().apply {
values().forEach { this[it.displayName] = it.getRequestsToURL(metricsEndpoint) }
}
}

fun getRequestsToURL(metricsEndpoint: MetricsEndpoint) = metricsEndpoint.requestsToURL(endpoint)

}

fun MetricsEndpoint.requestsToURL(url: String): Int {
val metric = metric("http.server.requests", listOf("uri:$url"))
metric ?: return 0
val count = metric.measurements.find { it.statistic == Statistic.COUNT }
count ?: return 0
return count.value.toInt()
}
39 changes: 39 additions & 0 deletions core/src/main/kotlin/net/osable/core/SecurityConfiguration.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package net.osable.core

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpStatus
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.authentication.HttpStatusEntryPoint
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler
import org.springframework.security.web.csrf.CookieCsrfTokenRepository
import org.springframework.web.bind.annotation.RestController

@Configuration
class SecurityConfiguration {

@Bean fun filterChain(http: HttpSecurity): SecurityFilterChain {
http.authorizeHttpRequests {

// Configure access to /admin
it.requestMatchers("/admin").fullyAuthenticated()

// Configure access to blog upload
it.requestMatchers("/blogs", "/blogs/upload").fullyAuthenticated()

// Configure access to the rest of the site
it.requestMatchers("/**").permitAll()
.anyRequest().authenticated()

}.csrf {
// Configure CSRF token
it.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
}.oauth2ResourceServer()

return http.build()
}

}
Loading

0 comments on commit c7984de

Please sign in to comment.