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")]
|
#[get("/.within/botinfo")]
|
||||||
fn botinfo() -> &'static str {
|
fn botinfo() -> &'static str {
|
||||||
r#"Hello, if you are reading this, you have found this URL in your
|
include_str!("./botinfo.txt")
|
||||||
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."#
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
|
|
@ -15,6 +15,18 @@
|
||||||
<h1>{{ title }}</h1>
|
<h1>{{ title }}</h1>
|
||||||
<p>{{ message }}</p>
|
<p>{{ message }}</p>
|
||||||
<a href="/">Go home</a>
|
<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>
|
</main>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -24,6 +24,9 @@ in pkgs.mkShell rec {
|
||||||
elm2nix
|
elm2nix
|
||||||
nodePackages.uglify-js
|
nodePackages.uglify-js
|
||||||
|
|
||||||
|
# tools
|
||||||
|
entr
|
||||||
|
|
||||||
# keep this line if you use bash
|
# keep this line if you use bash
|
||||||
bashInteractive
|
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
|
#!/usr/bin/env nix-shell
|
||||||
#! nix-shell -i bash -p elmPackages.elm
|
#! nix-shell -i bash -p elmPackages.elm
|
||||||
|
|
||||||
|
echo "--------------- rebuilding ------------------"
|
||||||
elm make ./src/Main.elm --output elm.js
|
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 Browser exposing (Document)
|
||||||
import Html exposing (Html, a, div, h1, main_, nav, text)
|
import Html exposing (Html, a, div, h1, main_, nav, text)
|
||||||
import Html.Attributes exposing (class, href)
|
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 : String -> List (Html msg) -> Document msg
|
||||||
template title body =
|
template title body =
|
||||||
{ title = title
|
{ title = title
|
||||||
|
|
|
@ -1,67 +1,146 @@
|
||||||
module Main exposing (main)
|
module Main exposing (main)
|
||||||
|
|
||||||
import Browser
|
import Browser exposing (Document, UrlRequest(..))
|
||||||
import Html exposing (Html, div, h1, img, p, pre, text)
|
import Browser.Navigation as Nav
|
||||||
import Html.Attributes exposing (src)
|
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 Http
|
||||||
import Layout
|
import Layout
|
||||||
import Mi
|
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
|
{-| All of the data that the app can hold.
|
||||||
= Failure String
|
-}
|
||||||
| Loading
|
type alias Model =
|
||||||
| Success String
|
{ navKey : Nav.Key
|
||||||
|
, route : Maybe Route
|
||||||
|
, token : Maybe String
|
||||||
|
, tokenData : Maybe Mi.TokenData
|
||||||
|
, error : Maybe String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
init : () -> ( Model, Cmd Msg )
|
init : () -> Url -> Nav.Key -> ( Model, Cmd Msg )
|
||||||
init _ =
|
init _ url key =
|
||||||
( Loading
|
( { navKey = key
|
||||||
, Http.get
|
, route = UrlParser.parse routeParser url
|
||||||
{ url = "/.within/botinfo"
|
, token = Nothing
|
||||||
, expect = Http.expectString GotText
|
, tokenData = Nothing
|
||||||
}
|
, error = Nothing
|
||||||
|
}
|
||||||
|
, Cmd.none
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
type Msg
|
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 -> ( Model, Cmd Msg )
|
||||||
update msg model =
|
update msg model =
|
||||||
case msg of
|
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
|
case result of
|
||||||
Ok fullText ->
|
Ok data ->
|
||||||
( Success fullText, Cmd.none )
|
( { model | tokenData = Just data }
|
||||||
|
, Nav.pushUrl model.navKey "/"
|
||||||
|
)
|
||||||
|
|
||||||
Err why ->
|
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 =
|
view model =
|
||||||
case model of
|
case model.error of
|
||||||
Failure why ->
|
Nothing ->
|
||||||
Layout.template "Error"
|
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
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
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" ]
|
||||||
|
]
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
Debug.todo "implement routing"
|
||||||
|
|
||||||
|
Just why ->
|
||||||
|
Layout.basic
|
||||||
|
"Error"
|
||||||
[ p [] [ text why ]
|
[ p [] [ text why ]
|
||||||
]
|
, a [ onClick ClearError, href "/" ] [ text "Clear error" ]
|
||||||
|
|
||||||
Loading ->
|
|
||||||
Layout.template "Loading" []
|
|
||||||
|
|
||||||
Success msg ->
|
|
||||||
Layout.template "Mi"
|
|
||||||
[ pre [] [ text msg ]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
main : Program () Model Msg
|
main : Program () Model Msg
|
||||||
main =
|
main =
|
||||||
Browser.document
|
Browser.application
|
||||||
{ view = view
|
{ view = view
|
||||||
, init = init
|
, init = init
|
||||||
, update = update
|
, update = update
|
||||||
, subscriptions = always Sub.none
|
, 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