Compare commits

..

4 Commits

Author SHA1 Message Date
httpjamesm 23802fcf5b Merge branch 'main' into fix/replace-relative-urls-with-absolute-ones 2024-06-13 02:19:06 -04:00
httpjamesm 71dec733b0 fix: don't prepend if the prefix is already in the URL 2024-06-13 02:07:41 -04:00
httpjamesm 5b01a5c232 feat: prepend /exchange/:sub to relative anchor hrefs in question bodies 2024-06-13 02:03:15 -04:00
httpjamesm f2ccff9f1a feat: ConvertRelativeAnchorURLsToAbsolute 2024-06-13 01:56:28 -04:00
20 changed files with 166 additions and 189 deletions
+1 -4
View File
@@ -11,18 +11,15 @@ COPY . .
ENV CGO_ENABLED=0
RUN go build -o anonymousoverflow && go build -o healthcheck ./src/healthcheck
RUN go build -o anonymousoverflow
FROM scratch
COPY --from=build /app/anonymousoverflow /anonymousoverflow
COPY --from=build /app/healthcheck /healthcheck
COPY templates /templates
COPY public /public
COPY --from=build /etc/ssl/certs /etc/ssl/certs
HEALTHCHECK --interval=60s --timeout=5s --start-period=2s --retries=3 CMD [ "/healthcheck","http://localhost:8080/healthz" ]
EXPOSE 8080
CMD ["/anonymousoverflow"]
+10 -31
View File
@@ -5,7 +5,7 @@ go 1.19
require (
github.com/PuerkitoBio/goquery v1.9.1
github.com/alecthomas/chroma v0.10.0
github.com/gin-gonic/gin v1.10.0
github.com/gin-gonic/gin v1.9.1
github.com/go-resty/resty/v2 v2.12.0
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/joho/godotenv v1.5.1
@@ -13,55 +13,34 @@ require (
require (
github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/bytedance/sonic v1.11.3 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.11.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/go-playground/validator/v10 v10.19.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/influxdata/influxdb-client-go/v2 v2.13.0 // indirect
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.16.7 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
github.com/oapi-codegen/runtime v1.0.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/redis/go-redis/v9 v9.5.3 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/tavsec/gin-healthcheck v1.6.2 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
go.mongodb.org/mongo-driver v1.15.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
golang.org/x/arch v0.7.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
-67
View File
@@ -2,26 +2,16 @@ github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0g
github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
github.com/PuerkitoBio/goquery v1.9.1 h1:mTL6XjbJTZdpfL+Gwl5U2h1l9yEkJjhmlTeV9VPW7UI=
github.com/PuerkitoBio/goquery v1.9.1/go.mod h1:cW1n6TmIMDoORQU5IU/P1T3tGFunOeXEpGP2WHRwkbY=
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
github.com/bytedance/sonic v1.11.3 h1:jRN+yEjakWh8aK5FzrciUHG8OFXK+4/KrAX/ysEtHAA=
github.com/bytedance/sonic v1.11.3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
@@ -29,16 +19,10 @@ github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpV
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
@@ -52,8 +36,6 @@ github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY=
github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398=
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
@@ -69,8 +51,6 @@ github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJ
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=
github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
github.com/go-resty/resty/v2 v2.12.0 h1:rsVL8P90LFvkUYq/V5BTVe203WfRIU4gvcf+yfzJzGA=
@@ -84,26 +64,15 @@ github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/influxdata/influxdb-client-go/v2 v2.13.0 h1:ioBbLmR5NMbAjP4UVA5r9b5xGjpABD7j65pI8kFphDM=
github.com/influxdata/influxdb-client-go/v2 v2.13.0/go.mod h1:k+spCbt9hcvqvUiz0sr5D8LolXHqAAOfPw9v/RIRHl4=
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
@@ -129,25 +98,16 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/oapi-codegen/runtime v1.0.0 h1:P4rqFX5fMFWqRzY9M/3YF9+aPSPPB06IzP2P7oOxrWo=
github.com/oapi-codegen/runtime v1.0.0/go.mod h1:LmCUMQuPB4M/nLXilQXhHw+BLZdDb18B34OO356yJ/A=
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo=
github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.5.3 h1:fOAp1/uJG+ZtcITgZOfYFmTKPE7n4Vclj1wZFgRciUU=
github.com/redis/go-redis/v9 v9.5.3/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -162,30 +122,16 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tavsec/gin-healthcheck v1.6.2 h1:F89IFXXtYOy3p4gne8WFkos3r7vjMbE+R3C/v70dTW0=
github.com/tavsec/gin-healthcheck v1.6.2/go.mod h1:VcZ4f44KqMnwbzRBrr7VYni2GmkMErd/44QuM5Dy/YI=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.8 h1:sgBJS6COt0b/P40VouWKdseidkDgHxYGm0SAglUHfP0=
github.com/ugorji/go/codec v1.2.8/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc=
go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
@@ -195,8 +141,6 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -214,13 +158,9 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -238,8 +178,6 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -251,14 +189,11 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -272,8 +207,6 @@ google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+2 -7
View File
@@ -71,9 +71,9 @@
"operators": ["https://freedit.eu"]
},
{
"url": "https://ao.rootdo.com",
"url": "https://ao.ftw.lol",
"regions": ["Germany"],
"operators": ["https://rootdo.com"]
"operators": ["https://ftw.lol"]
},
{
"url": "https://anonoverflow.nirn.quest",
@@ -144,11 +144,6 @@
"url": "https://overflow.darkness.services/",
"regions": ["United States"],
"operators": ["https://zzz.darkness.services"]
},
{
"url": "https://anonflow.aketawi.space/",
"regions": ["Russia"],
"operators": ["https://www.aketawi.space/"]
}
],
+1 -7
View File
@@ -8,9 +8,6 @@ import (
"os"
"github.com/gin-gonic/gin"
healthcheck "github.com/tavsec/gin-healthcheck"
"github.com/tavsec/gin-healthcheck/checks"
"github.com/tavsec/gin-healthcheck/config"
)
func main() {
@@ -38,6 +35,7 @@ func main() {
r.Use(gin.Recovery())
r.Use(middleware.XssPreventionHeaders())
r.Use(middleware.NoCacheMiddleware())
r.Use(middleware.OptionsMiddleware())
r.Use(middleware.Ratelimit())
@@ -86,9 +84,5 @@ func main() {
r.GET("/proxy", routes.GetImage)
soPingCheck := checks.NewPingCheck("https://stackoverflow.com", "GET", 5000, nil, nil)
sePingCheck := checks.NewPingCheck("https://stackexchange.com", "GET", 5000, nil, nil)
healthcheck.New(r, config.DefaultConfig(), []checks.Check{soPingCheck, sePingCheck})
r.Run(fmt.Sprintf("%s:%s", host, port))
}
+6 -21
View File
@@ -1,13 +1,9 @@
:root {
--code-bg: #36383d;
--code-fg: #ffffff;
}
:root,
[data-theme="dark"] {
--main-bg: #1b1f26;
--text-color: #fff;
--muted-text-color: #b3b3b3;
--code-bg: #36383d;
--code-fg: #ffffff;
--input-bg: #2b303b;
--input-bg-hover: #3b404b;
--meta-bg: #525262;
@@ -15,23 +11,12 @@
--link-color: #92adff;
}
@media (prefers-color-scheme: light) {
:root:not([data-theme="dark"]) {
--main-bg: #dbdbdb;
--text-color: #000;
--muted-text-color: #636363;
--input-bg: #bcbcbc;
--input-bg-hover: #a8a8a8;
--meta-bg: #aaa8a8;
--divider-color: #b5b5b5;
--link-color: #335ad0;
}
}
[data-theme="light"] {
[data-theme='light'] {
--main-bg: #dbdbdb;
--text-color: #000;
--muted-text-color: #636363;
--code-bg: #36383d;
--code-fg: #ffffff;
--input-bg: #bcbcbc;
--input-bg-hover: #a8a8a8;
--meta-bg: #aaa8a8;
@@ -91,4 +76,4 @@ details {
.fw-nowrap {
flex-wrap: nowrap;
}
}
-20
View File
@@ -1,20 +0,0 @@
package main
import (
"fmt"
"log"
"net/http"
"os"
)
func main() {
if len(os.Args) < 2 {
log.Fatal("Expected URL as command-line argument")
os.Exit(1)
}
url := os.Args[1]
fmt.Println(url)
if _, err := http.Get(url); err != nil {
os.Exit(1)
}
}
+12
View File
@@ -0,0 +1,12 @@
package middleware
import "github.com/gin-gonic/gin"
func NoCacheMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Cache-Control", "no-cache, no-store, must-revalidate")
c.Header("Pragma", "no-cache")
c.Header("Expires", "0")
c.Next()
}
}
+8
View File
@@ -7,6 +7,7 @@ import (
func OptionsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Set("disable_images", false)
c.Set("theme", "dark")
imagesCookie, err := c.Cookie("disable_images")
if err == nil {
@@ -15,6 +16,13 @@ func OptionsMiddleware() gin.HandlerFunc {
}
}
themeCookie, err := c.Cookie("theme")
if err == nil {
if themeCookie == "light" {
c.Set("theme", "light")
}
}
c.Next()
}
}
+1
View File
@@ -47,6 +47,7 @@ func Ratelimit() gin.HandlerFunc {
if val.(int) > 30 {
c.HTML(429, "home.html", gin.H{
"errorMessage": "You have exceeded the request limit. Please try again in a minute.",
"theme": c.MustGet("theme").(string),
"version": config.Version,
})
c.Abort()
+3 -5
View File
@@ -2,7 +2,6 @@ package routes
import (
"anonymousoverflow/config"
"anonymousoverflow/src/utils"
"fmt"
"regexp"
"strings"
@@ -11,10 +10,9 @@ import (
)
func GetHome(c *gin.Context) {
theme := utils.GetThemeFromEnv()
c.HTML(200, "home.html", gin.H{
"version": config.Version,
"theme": theme,
"theme": c.MustGet("theme").(string),
})
}
@@ -64,6 +62,7 @@ func PostHome(c *gin.Context) {
if err := c.ShouldBind(&body); err != nil {
c.HTML(400, "home.html", gin.H{
"errorMessage": "Invalid request body",
"theme": c.MustGet("theme").(string),
})
return
}
@@ -71,10 +70,9 @@ func PostHome(c *gin.Context) {
translated := translateUrl(body.URL)
if translated == "" {
theme := utils.GetThemeFromEnv()
c.HTML(400, "home.html", gin.H{
"errorMessage": "Invalid stack overflow/exchange URL",
"theme": theme,
"theme": c.MustGet("theme").(string),
})
return
}
+20 -3
View File
@@ -2,8 +2,9 @@ package routes
import (
"anonymousoverflow/config"
"anonymousoverflow/src/utils"
"fmt"
"os"
"strings"
"github.com/gin-gonic/gin"
)
@@ -18,12 +19,28 @@ func ChangeOptions(c *gin.Context) {
text = "enabled"
}
c.SetCookie("disable_images", fmt.Sprintf("%t", !c.MustGet("disable_images").(bool)), 60*60*24*365*10, "/", "", false, true)
theme := utils.GetThemeFromEnv()
c.HTML(200, "home.html", gin.H{
"successMessage": "Images are now " + text,
"theme": c.MustGet("theme").(string),
"version": config.Version,
"theme": theme,
})
case "theme":
text := "dark"
if c.MustGet("theme").(string) == "dark" {
text = "light"
}
c.SetCookie("theme", text, 60*60*24*365*10, "/", "", false, true)
// get redirect url from query
redirectUrl := c.Query("redirect_url")
if !strings.HasPrefix(redirectUrl, os.Getenv("APP_URL")) {
redirectUrl = os.Getenv("APP_URL")
}
c.Redirect(302, redirectUrl)
default:
c.String(400, "400 Bad Request")
}
+18 -8
View File
@@ -34,6 +34,7 @@ func ViewQuestion(c *gin.Context) {
if _, err := strconv.Atoi(questionId); err != nil {
c.HTML(400, "home.html", gin.H{
"errorMessage": "Invalid question ID",
"theme": c.MustGet("theme").(string),
"version": config.Version,
})
return
@@ -59,6 +60,7 @@ func ViewQuestion(c *gin.Context) {
if resp.StatusCode() != 200 {
c.HTML(500, "home.html", gin.H{
"errorMessage": fmt.Sprintf("Received a non-OK status code %d", resp.StatusCode()),
"theme": c.MustGet("theme").(string),
"version": config.Version,
})
return
@@ -72,15 +74,17 @@ func ViewQuestion(c *gin.Context) {
if err != nil {
c.HTML(500, "home.html", gin.H{
"errorMessage": "Unable to parse question data",
"theme": c.MustGet("theme").(string),
"version": config.Version,
})
return
}
newFilteredQuestion, err := extractQuestionData(doc, domain)
newFilteredQuestion, err := extractQuestionData(doc, domain, params.Sub)
if err != nil {
c.HTML(500, "home.html", gin.H{
"errorMessage": "Failed to extract question data",
"theme": c.MustGet("theme").(string),
"version": config.Version,
})
return
@@ -90,6 +94,7 @@ func ViewQuestion(c *gin.Context) {
if err != nil {
c.HTML(500, "home.html", gin.H{
"errorMessage": "Failed to extract answer data",
"theme": c.MustGet("theme").(string),
"version": config.Version,
})
return
@@ -101,16 +106,14 @@ func ViewQuestion(c *gin.Context) {
imagePolicy = "'self'"
}
theme := utils.GetThemeFromEnv()
c.HTML(200, "question.html", gin.H{
"question": newFilteredQuestion,
"answers": answers,
"imagePolicy": imagePolicy,
"theme": c.MustGet("theme").(string),
"currentUrl": fmt.Sprintf("%s%s", os.Getenv("APP_URL"), c.Request.URL.Path),
"sortValue": params.SoSortValue,
"domain": domain,
"theme": theme,
})
}
@@ -129,6 +132,7 @@ func parseAndValidateParameters(c *gin.Context) (inputs viewQuestionInputs, err
if _, err = strconv.Atoi(questionId); err != nil {
c.HTML(400, "home.html", gin.H{
"errorMessage": "Invalid question ID",
"theme": c.MustGet("theme").(string),
"version": config.Version,
})
return
@@ -163,7 +167,7 @@ func fetchQuestionData(soLink string) (resp *resty.Response, err error) {
}
// extractQuestionData parses the HTML document and extracts question data.
func extractQuestionData(doc *goquery.Document, domain string) (question types.FilteredQuestion, err error) {
func extractQuestionData(doc *goquery.Document, domain, exchangeSub string) (question types.FilteredQuestion, err error) {
// Extract the question title.
questionTextParent := doc.Find("h1.fs-headline1").First()
question.Title = strings.TrimSpace(questionTextParent.Children().First().Text())
@@ -178,7 +182,15 @@ func extractQuestionData(doc *goquery.Document, domain string) (question types.F
if err != nil {
return question, err
}
question.Body = template.HTML(utils.ProcessHTMLBody(questionBodyParentHTML))
questionBodyParentHTML = utils.ProcessHTMLBody(questionBodyParentHTML)
// If there's an exchange sub, prepend the /exchange/:sub prefix to prevent unintended platform switching.
if exchangeSub != "" {
questionBodyParentHTML = utils.ConvertRelativeAnchorURLsToAbsolute(questionBodyParentHTML, fmt.Sprintf("/exchange/%s", exchangeSub))
}
question.Body = template.HTML(questionBodyParentHTML)
// Extract the shortened body description.
shortenedBody := strings.TrimSpace(questionBodyParent.Text())
@@ -227,8 +239,6 @@ func extractAnswersData(doc *goquery.Document, domain string) ([]types.FilteredA
doc.Find("div.answer").Each(func(i int, s *goquery.Selection) {
var answer types.FilteredAnswer
answer.ID = s.AttrOr("data-answerid", "")
postLayout := s.Find("div.post-layout").First()
// Extract upvotes.
+2
View File
@@ -33,6 +33,7 @@ func RedirectShortenedOverflowURL(c *gin.Context) {
if err != nil {
c.HTML(400, "home.html", gin.H{
"errorMessage": "Unable to fetch stack overflow URL",
"theme": c.MustGet("theme").(string),
})
return
}
@@ -40,6 +41,7 @@ func RedirectShortenedOverflowURL(c *gin.Context) {
if resp.StatusCode() != 302 {
c.HTML(400, "home.html", gin.H{
"errorMessage": fmt.Sprintf("Unexpected HTTP status from origin: %d", resp.StatusCode()),
"theme": c.MustGet("theme").(string),
})
return
}
+27 -1
View File
@@ -42,4 +42,30 @@ func ReplaceStackOverflowLinks(html string) string {
// Replace the href attribute value in the anchor tag
return strings.Replace(match, hrefMatch[1], newUrl, 1)
})
}
}
var relativeAnchorURLRegex = regexp.MustCompile(`href="(/[^"]+)"`)
func ConvertRelativeAnchorURLsToAbsolute(html, prefix string) string {
if prefix == "" {
return html
}
if !strings.HasSuffix(prefix, "/") {
prefix += "/"
}
return relativeAnchorURLRegex.ReplaceAllStringFunc(html, func(match string) string {
// Extract the URL from the match
url := strings.TrimPrefix(match, `href="`)
url = strings.TrimSuffix(url, `"`)
// If the URL already has the desired prefix, return the match as is
if strings.HasPrefix(url, prefix) {
return match
}
// Otherwise, prepend the prefix
return strings.Replace(match, `href="/`, `href="`+prefix, 1)
})
}
+44 -1
View File
@@ -2,9 +2,11 @@ package utils
import (
"fmt"
"github.com/stretchr/testify/assert"
"log"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
var sampleInput = `<div class="d-flex fd-column fw-nowrap">
@@ -47,3 +49,44 @@ func TestReplaceStackOverflowLinks(t *testing.T) {
assert.False(t, strings.Contains(replacedLinks, "stackoverflow.com"))
assert.False(t, strings.Contains(replacedLinks, "stackexchange.com"))
}
var sampleRelativeAnchorURLsInput = `<aside class="s-notice s-notice__info post-notice js-post-notice mb16" role="status">
<div class="d-flex fd-column fw-nowrap">
<div class="d-flex fw-nowrap">
<div class="flex--item wmn0 fl1 lh-lg">
<div class="flex--item fl1 lh-lg">
<div>
<b>This question already has an answer here</b>:
</div>
</div>
</div>
</div>
<div class="flex--item mb0 mt4">
<a href="/questions/5771/is-it-possible-to-restrict-gnu-gplv3-to-non-commercial-use-only" dir="ltr">Is it possible to restrict GNU GPLv3 to non-commercial use only?</a>
<span class="question-originals-answer-count">
(1 answer)
</span>
</div>
<div class="flex--item mb0 mt8">Closed <span title="2018-09-30 22:47:30Z" class="relativetime">5 years ago</span>.</div>
</div>
</aside>
<div class="answer-author-parent">
<div class="answer-author">
Answered Sep 27, 2018 at 21:21 by
<a href="https://notopensource.stackexchange.com/users/1212/amon" target="_blank" rel="noopener noreferrer">amon</a>
</div>
</div>
<a href="/exchange/opensource/9999/1111">This shouldn't be re-prefixed</a>
`
func TestConvertRelativeAnchorURLsToAbsolute(t *testing.T) {
prefix := "/exchange/opensource"
fixedHTML := ConvertRelativeAnchorURLsToAbsolute(sampleRelativeAnchorURLsInput, prefix)
log.Println(fixedHTML)
assert.True(t, strings.Contains(fixedHTML, prefix))
assert.True(t, strings.Contains(fixedHTML, "https://notopensource.stackexchange.com"))
}
-11
View File
@@ -1,11 +0,0 @@
package utils
import "os"
func GetThemeFromEnv() string {
theme := os.Getenv("THEME")
if theme == "" {
theme = "auto"
}
return theme
}
+3 -2
View File
@@ -43,9 +43,10 @@
<div class="options">
<div class="icon">
<a href="/options/images">
<img src="/static/icons/image.svg" alt="Toggle images" />
<img src="/static/icons/image.svg" alt="Toggle theme" />
</a>
</div>
{{ template "themeSwitcher.html" .}}
</div>
<p class="footer">
Brought to you by
@@ -58,4 +59,4 @@
</div>
</body>
</html>
</html>
+2 -1
View File
@@ -25,6 +25,7 @@
<a href="/" class="logo-link">
<img class="logo" src="/static/codecircles.webp" alt="AnonymousOverflow home" />
</a>
{{ template "themeSwitcher.html" . }}
</div>
<div class="card">
<div class="card-header">
@@ -92,4 +93,4 @@
{{ end }}
</body>
</html>
</html>
+6
View File
@@ -0,0 +1,6 @@
<div class="icon">
<a href="/options/theme?redirect_url={{ .currentUrl }}">
<img src="/static/icons/{{ if eq .theme "dark" }}sun{{
else }}moon{{ end }}.svg" alt="Toggle theme" />
</a>
</div>