This repository contains the files for the itunderground.dk website. The main
branch has the source, while the gh-pages
branch is the live static page.
The website itself is a simulation of a Linux shell in the browser, made using SvelteKit. It also supposed blog-like contents in the form of markdown files, located in src/routes/post/
.
There are two user-friendly ways to extend the website. Markdown files and commands.
To extend, you first need to set up a local development environment.
- Git: https://git-scm.com/downloads
- Node.js: https://nodejs.org/ (Most newer versions should work, project was last built with v20).
- pnpm: https://pnpm.io/installation (you can probably use npm if you change
pnpm
tonpm
inpackage.json
.)
Clone this repository to your machine:
git clone https://github.com/ITUnderground/itunderground.dk
Once it's been cloned, enter it and install the npm packages.
cd itunderground.dk
pnpm install # Note: You can also choose to use npm, but pnpm is preferred
To run the website locally use following command:
pnpm run dev
It will host the website on localhost:5173.
Once you're confident with your changes, push them to GitHub and the Actions Workflow will automatically update the site:
git add .
git commit -m "Write what you changed here"
git push
❗ Warning
Pushing to themaster
branch will immediately update the LIVE version on itunderground.dk, so make sure all your changes are final before pushing.
Once you've set up a local environment, you can begin updating the website.
There are 3 main elements of itunderground.dk:
Markdown files are used for blog-like posts. An example of this is itunderground.dk/post/who-are-we. The corresponding markdown file is located in src/routes/post/who-are-we/+page.md
.
To render markdown, we use mdsvex. It supports both .md files and .svx files, and both support directly inserting Svelte components. That means you can for example create a dynamic markdown file that fetches data from some server (remember, the site is static so make sure any data fetching happens client-side!).
Dynamic data fetching in markdown components has not yet been used on our site, but feel free to add it to the readme if you decide to utilize it.
To add a markdown file, create a directory corresponding to its name and add a +page.md
file. Remember to link to the file somewhere, such as in the default filesystem or there won't be a way to navigate to it (This is not necessary for writeups unless starting a new CTF. Their links are automatically updated).
Push your changes to GitHub to see the updated website.
All commands in the Linux shell are custom implementations written in TypeScript. They're located in src/lib/shell/commands/
, with some built-in core commands located in builtin/
.
To add a command create a new TypeScript file in the commands/
directory with the name of the command you want to implement. Copy the following template:
import Command from '../command';
export default new Command({
command({ cli, dir, env, js, command }) {
// Logic here
const flagValue = command.namedArguments['userflag'];
cli.stdout('Hello world!');
return `You passed the flag ${flagValue}!`;
},
description: 'My cool and awesome command.',
namedArguments: [
{
name: 'userflag',
choices: ['flag', 'userflag', 'f'],
hasValue: true
}
]
});
It is highly recommanded that you use something like IntelliSense to view all properties on the AccesObject that your command has access to. It can also be helpful to look at the type definitions in src/lib/shell/types.d.ts
. Methods starting with and underscore (_) should be avoided as they are meant for internal use. See other commands for inspiration on how to make use of this object.
- The AccessObject contains all the metadata you have access to in the command.
cli
: Exposes basic CLI methods that allows you to run a command and print to regular output, as well as the log.
Seeclear
andsudo
for commands that use this object.dir
: Exposes directory related methods, like current working directory and methods to get directories and files.
Seecd
andls
for commands that use this object.env
: Exposes methods related to environment variables, likeget
andset
.
Seebuiltin/echo
for a command that uses this object.js
: Allow you to execute JavaScript in the browser.
Seeneofetch
for a command that uses this function.command
: Information about the command that was run. This object contains the arguments of the command.
name
is the name of the command, aka. the first word of the input.positionalArguments
are arguments relative to a command. That is, incat file.txt
,file.txt
would be the first positional argument. This is a list of strings.
namedArguments
are arguments passed as flags. That is, inpython -m script
,script
is the value of the named argument-m
. To receivenamedArguments
, they must be defined in thenamedArguments
section. In the example above, the argument named "userflag" can be passed to the command using either--flag
,--userflag
or-f
. Internally, its name is "userflag", and it expects a value. IfhasValue
is nullable, the value of the argument will simply betrue
if it is present. The value of any argument not passed by the user isfalse
.
Note: If an argument withhasValue: true
is passed to the command without a value, it will have valueundefined
. If the argument is not passed to the command, it will have valuefalse
.raw
is the raw string command.
Seecat
andsudo
for commands that implement this object.
- There are 2 ways to write output from the command. The first is to use
cli.stdout()
, the second is to return a string. The latter is preferred. The command does not have to return anything, but if it does it this should be a string (or a promise of a string/void).
Note that any HTML in bothcli.stdout
and return value will be rendered, though script tag will not execute (see for exampleneofetch
). - Commands can be asynchronous and return promises. Note that async commands are currently blocking. See
neofetch
for async usage.
Finally, to be able to use the command, add it in commands/index.ts
. Commands not defined in this file will not work.