hey i have http stuff working
This commit is contained in:
parent
cd8a820d57
commit
73aad7ab62
|
@ -0,0 +1,15 @@
|
|||
Hello, if you are reading this, you have found this URL in your
|
||||
access logs. If this program is doing something you don't want it to do,
|
||||
please contact me at me@christine.website.
|
||||
|
||||
This service is intended to act as a POSSE[1] syndication server for
|
||||
various services to various other services.
|
||||
|
||||
Every effort is being taken to ensure that the data going through this
|
||||
server is my own.
|
||||
|
||||
I'm sorry if this causes you any inconvenience.
|
||||
|
||||
[1]: https://indieweb.org/POSSE
|
||||
|
||||
Be well, Creator.
|
|
@ -15,21 +15,7 @@ use ::mi::{api, frontend, paseto, rocket_trace::*, web::*, MainDatabase, APPLICA
|
|||
|
||||
#[get("/.within/botinfo")]
|
||||
fn botinfo() -> &'static str {
|
||||
r#"Hello, if you are reading this, you have found this URL in your
|
||||
access logs. If this program is doing something you don't want it to do,
|
||||
please contact me at me@christine.website.
|
||||
|
||||
This service is intended to act as a POSSE[1] syndication server for
|
||||
various services to various other services.
|
||||
|
||||
Every effort is being taken to ensure that the data going through this
|
||||
server is my own.
|
||||
|
||||
I'm sorry if this causes you any inconvenience.
|
||||
|
||||
[1]: https://indieweb.org/POSSE
|
||||
|
||||
Be well, Creator."#
|
||||
include_str!("./botinfo.txt")
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
|
|
|
@ -15,6 +15,18 @@
|
|||
<h1>{{ title }}</h1>
|
||||
<p>{{ message }}</p>
|
||||
<a href="/">Go home</a>
|
||||
|
||||
<div id="app"></div>
|
||||
<script src="/static/elm.js"></script>
|
||||
<script>
|
||||
var app = Elm.Main.init({
|
||||
node: document.getElementById("app")
|
||||
});
|
||||
</script>
|
||||
<noscript>
|
||||
You must enable JavaScript for this page to work.
|
||||
</noscript>
|
||||
<script src="/static/install-sw.js"></script>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -24,6 +24,9 @@ in pkgs.mkShell rec {
|
|||
elm2nix
|
||||
nodePackages.uglify-js
|
||||
|
||||
# tools
|
||||
entr
|
||||
|
||||
# keep this line if you use bash
|
||||
bashInteractive
|
||||
];
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env nix-shell
|
||||
#! nix-shell -i bash -p entr
|
||||
|
||||
find ./src/* | entr ./scripts/build-dev.sh
|
|
@ -1,4 +1,6 @@
|
|||
#!/usr/bin/env nix-shell
|
||||
#! nix-shell -i bash -p elmPackages.elm
|
||||
|
||||
echo "--------------- rebuilding ------------------"
|
||||
elm make ./src/Main.elm --output elm.js
|
||||
echo "------------------ done ---------------------"
|
||||
|
|
|
@ -1,10 +1,30 @@
|
|||
module Layout exposing (template)
|
||||
module Layout exposing (basic, template)
|
||||
|
||||
import Browser exposing (Document)
|
||||
import Html exposing (Html, a, div, h1, main_, nav, text)
|
||||
import Html.Attributes exposing (class, href)
|
||||
|
||||
|
||||
basic : String -> List (Html msg) -> Document msg
|
||||
basic title body =
|
||||
{ title = title
|
||||
, body =
|
||||
[ main_
|
||||
[]
|
||||
([ nav
|
||||
[ class "nav" ]
|
||||
[ a [ href "/" ] [ text "Mi" ]
|
||||
, text " - "
|
||||
, a [ href "/login" ] [ text "Login" ]
|
||||
]
|
||||
, h1 [] [ text title ]
|
||||
]
|
||||
++ body
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
template : String -> List (Html msg) -> Document msg
|
||||
template title body =
|
||||
{ title = title
|
||||
|
|
|
@ -1,67 +1,146 @@
|
|||
module Main exposing (main)
|
||||
|
||||
import Browser
|
||||
import Html exposing (Html, div, h1, img, p, pre, text)
|
||||
import Html.Attributes exposing (src)
|
||||
import Browser exposing (Document, UrlRequest(..))
|
||||
import Browser.Navigation as Nav
|
||||
import Html exposing (Html, a, br, button, div, h1, img, input, p, pre, span, text)
|
||||
import Html.Attributes exposing (href, placeholder, src, value)
|
||||
import Html.Events exposing (onClick, onInput)
|
||||
import Http
|
||||
import Layout
|
||||
import Mi
|
||||
import Mi.Switch
|
||||
import Mi.WebMention
|
||||
import Route exposing (Route(..), routeParser)
|
||||
import Url exposing (Url)
|
||||
import Url.Parser as UrlParser exposing ((</>))
|
||||
|
||||
|
||||
type Model
|
||||
= Failure String
|
||||
| Loading
|
||||
| Success String
|
||||
|
||||
|
||||
init : () -> ( Model, Cmd Msg )
|
||||
init _ =
|
||||
( Loading
|
||||
, Http.get
|
||||
{ url = "/.within/botinfo"
|
||||
, expect = Http.expectString GotText
|
||||
{-| All of the data that the app can hold.
|
||||
-}
|
||||
type alias Model =
|
||||
{ navKey : Nav.Key
|
||||
, route : Maybe Route
|
||||
, token : Maybe String
|
||||
, tokenData : Maybe Mi.TokenData
|
||||
, error : Maybe String
|
||||
}
|
||||
|
||||
|
||||
init : () -> Url -> Nav.Key -> ( Model, Cmd Msg )
|
||||
init _ url key =
|
||||
( { navKey = key
|
||||
, route = UrlParser.parse routeParser url
|
||||
, token = Nothing
|
||||
, tokenData = Nothing
|
||||
, error = Nothing
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
type Msg
|
||||
= GotText (Result Http.Error String)
|
||||
= ChangeUrl Url
|
||||
| ClickLink UrlRequest
|
||||
| UpdateToken String
|
||||
| SubmitToken
|
||||
| ValidateToken (Result Http.Error Mi.TokenData)
|
||||
| ClearError
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
GotText result ->
|
||||
UpdateToken newToken ->
|
||||
( { model | token = Just newToken }, Cmd.none )
|
||||
|
||||
ChangeUrl url ->
|
||||
( { model | route = UrlParser.parse routeParser url }, Cmd.none )
|
||||
|
||||
SubmitToken ->
|
||||
( model
|
||||
, Mi.request
|
||||
"GET"
|
||||
(Maybe.withDefault "" model.token)
|
||||
Mi.tokenIntrospectURL
|
||||
Http.emptyBody
|
||||
(Mi.expectJson ValidateToken Mi.tokenDecoder)
|
||||
)
|
||||
|
||||
ValidateToken result ->
|
||||
case result of
|
||||
Ok fullText ->
|
||||
( Success fullText, Cmd.none )
|
||||
Ok data ->
|
||||
( { model | tokenData = Just data }
|
||||
, Nav.pushUrl model.navKey "/"
|
||||
)
|
||||
|
||||
Err why ->
|
||||
( Failure (Mi.errorToString why), Cmd.none )
|
||||
( { model | error = Just <| Mi.errorToString why }, Cmd.none )
|
||||
|
||||
ClickLink urlRequest ->
|
||||
case urlRequest of
|
||||
Internal url ->
|
||||
( model, Nav.pushUrl model.navKey <| Url.toString url )
|
||||
|
||||
External url ->
|
||||
( model, Nav.load url )
|
||||
|
||||
ClearError ->
|
||||
( { model | error = Nothing, token = Nothing }, Cmd.none )
|
||||
|
||||
|
||||
view : Model -> Browser.Document msg
|
||||
view : Model -> Document Msg
|
||||
view model =
|
||||
case model of
|
||||
Failure why ->
|
||||
Layout.template "Error"
|
||||
[ p [] [ text why ]
|
||||
case model.error of
|
||||
Nothing ->
|
||||
case Maybe.withDefault Index model.route of
|
||||
Index ->
|
||||
case model.tokenData of
|
||||
Nothing ->
|
||||
Layout.basic "Login Required" []
|
||||
|
||||
Just data ->
|
||||
Layout.template "Mi"
|
||||
[ p
|
||||
[]
|
||||
[ span
|
||||
[]
|
||||
[ text "Subscriber: "
|
||||
, text data.sub
|
||||
, br [] []
|
||||
, text "Token ID: "
|
||||
, text data.jti
|
||||
, br [] []
|
||||
, text "Issuer: "
|
||||
, text data.iss
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
Loading ->
|
||||
Layout.template "Loading" []
|
||||
Login ->
|
||||
Layout.basic "Login"
|
||||
[ p [] [ text "Enter the secret code. Unauthorized access is prohibited." ]
|
||||
, input [ placeholder "API Token", value (Maybe.withDefault "" model.token), onInput UpdateToken ] []
|
||||
, button [ onClick SubmitToken ] [ text "Login" ]
|
||||
]
|
||||
|
||||
Success msg ->
|
||||
Layout.template "Mi"
|
||||
[ pre [] [ text msg ]
|
||||
_ ->
|
||||
Debug.todo "implement routing"
|
||||
|
||||
Just why ->
|
||||
Layout.basic
|
||||
"Error"
|
||||
[ p [] [ text why ]
|
||||
, a [ onClick ClearError, href "/" ] [ text "Clear error" ]
|
||||
]
|
||||
|
||||
|
||||
main : Program () Model Msg
|
||||
main =
|
||||
Browser.document
|
||||
Browser.application
|
||||
{ view = view
|
||||
, init = init
|
||||
, update = update
|
||||
, subscriptions = always Sub.none
|
||||
, onUrlRequest = ClickLink
|
||||
, onUrlChange = ChangeUrl
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
module Route exposing (..)
|
||||
|
||||
import Url.Parser exposing ((</>), (<?>), Parser, int, map, oneOf, s, string)
|
||||
import Url.Parser.Query as Query
|
||||
|
||||
|
||||
type Route
|
||||
= Index
|
||||
| Login
|
||||
| System
|
||||
| SwitchLog (Maybe Int)
|
||||
| SwitchID String
|
||||
| MakeSwitch
|
||||
| WebMentionLog (Maybe Int)
|
||||
| WebMentionID String
|
||||
|
||||
|
||||
routeParser : Parser (Route -> a) a
|
||||
routeParser =
|
||||
oneOf
|
||||
[ map Index (s "")
|
||||
, map Login (s "login")
|
||||
, map System (s "system")
|
||||
, map SwitchLog (s "switches" <?> Query.int "page")
|
||||
, map SwitchID (s "switches" </> string)
|
||||
, map MakeSwitch (s "switches" </> s "log")
|
||||
, map WebMentionLog (s "webmentions" <?> Query.int "page")
|
||||
, map WebMentionID (s "webmentions" </> string)
|
||||
]
|
|
@ -1,135 +0,0 @@
|
|||
// This optional code is used to register a service worker.
|
||||
// register() is not called by default.
|
||||
|
||||
// This lets the app load faster on subsequent visits in production, and gives
|
||||
// it offline capabilities. However, it also means that developers (and users)
|
||||
// will only see deployed updates on subsequent visits to a page, after all the
|
||||
// existing tabs open on the page have been closed, since previously cached
|
||||
// resources are updated in the background.
|
||||
|
||||
// To learn more about the benefits of this model and instructions on how to
|
||||
// opt-in, read https://bit.ly/CRA-PWA
|
||||
|
||||
const isLocalhost = Boolean(
|
||||
window.location.hostname === 'localhost' ||
|
||||
// [::1] is the IPv6 localhost address.
|
||||
window.location.hostname === '[::1]' ||
|
||||
// 127.0.0.1/8 is considered localhost for IPv4.
|
||||
window.location.hostname.match(
|
||||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
|
||||
)
|
||||
);
|
||||
|
||||
export function register(config) {
|
||||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||
// The URL constructor is available in all browsers that support SW.
|
||||
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
|
||||
if (publicUrl.origin !== window.location.origin) {
|
||||
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||
// from what our page is served on. This might happen if a CDN is used to
|
||||
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
||||
return;
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||
|
||||
if (isLocalhost) {
|
||||
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||
checkValidServiceWorker(swUrl, config);
|
||||
|
||||
// Add some additional logging to localhost, pointing developers to the
|
||||
// service worker/PWA documentation.
|
||||
navigator.serviceWorker.ready.then(() => {
|
||||
console.log(
|
||||
'This web app is being served cache-first by a service ' +
|
||||
'worker. To learn more, visit https://bit.ly/CRA-PWA'
|
||||
);
|
||||
});
|
||||
} else {
|
||||
// Is not localhost. Just register service worker
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function registerValidSW(swUrl, config) {
|
||||
navigator.serviceWorker
|
||||
.register(swUrl)
|
||||
.then(registration => {
|
||||
registration.onupdatefound = () => {
|
||||
const installingWorker = registration.installing;
|
||||
if (installingWorker == null) {
|
||||
return;
|
||||
}
|
||||
installingWorker.onstatechange = () => {
|
||||
if (installingWorker.state === 'installed') {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
// At this point, the updated precached content has been fetched,
|
||||
// but the previous service worker will still serve the older
|
||||
// content until all client tabs are closed.
|
||||
console.log(
|
||||
'New content is available and will be used when all ' +
|
||||
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
|
||||
);
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onUpdate) {
|
||||
config.onUpdate(registration);
|
||||
}
|
||||
} else {
|
||||
// At this point, everything has been precached.
|
||||
// It's the perfect time to display a
|
||||
// "Content is cached for offline use." message.
|
||||
console.log('Content is cached for offline use.');
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onSuccess) {
|
||||
config.onSuccess(registration);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during service worker registration:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function checkValidServiceWorker(swUrl, config) {
|
||||
// Check if the service worker can be found. If it can't reload the page.
|
||||
fetch(swUrl)
|
||||
.then(response => {
|
||||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (
|
||||
response.status === 404 ||
|
||||
(contentType != null && contentType.indexOf('javascript') === -1)
|
||||
) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.unregister().then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Service worker found. Proceed as normal.
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.log(
|
||||
'No internet connection found. App is running in offline mode.'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function unregister() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.unregister();
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue