-
-
Notifications
You must be signed in to change notification settings - Fork 572
Authentication
If you want to restrict the users that can use the terminal, you can use authentication. The way jQuery Terminal implements authentication is using a token. The token is a way to validate if the client and server are the same people. The token is any true value, but ideally, it should be a unique identifier that can be validated on the server. Example result of any hash function like md5 (I think you don't need to worry about collisions in the token, but you can use a more secured hash if you want) on current time saved in a safe place, like the database or a session.
The simplest way of authentication is login
option. If you have a JSON-RPC interpreter you can set this option to true
or stings and it will call the login RPC method or method specified by the option and if RPC returns a truthy value, the best is token hash as string, it
will log you in the terminal. And from now on each call to the RPC method will have a token as the first argument so each method on the server should check if the token is valid.
And since the token is just a string, you can use JWT as a token.
Examples
$('body').terminal('service.php', {
login: true
});
$('body').terminal('service.php', {
login: "auth"
});
and JSON-RPC service requires each procedure to have a token as the first argument and validate it. It should throw an error if the token is invalid. When this happens the command will show an error on the terminal. You can use any implementation of JSON-RPC in your server-side language of choice.
You can also specify a function as login, where you can use naive check for the password in JavaScript or call the server to verify the user (you don't need to use JSON-RPC but it requires more code), which is a proper way to do.
$(function() {
$('#terminal').terminal({}, {
login: function(user, password) {
return fetch('auth.py', {
method: 'POST',
body: JSON.stringify({user, password}),
headers:{
'Content-Type': 'application/json'
}
}).then(res => res.json());
}
});
});
and auth.py
should read JSON as POST data to validate that this is a valid user and if so generate a token (any value) and save it in a safe place (that can't be accessed from the web).
Here we use fetch API to send POST request to the server in auth.py
URI and whatever JSON it returns it will be used as a token, the server needs to return JSON string (texts "<generated token>"
) or null (false will also work). auth.py
should read JSON as POST data to validate that this is a valid user and if so generate a token (any value) and save it in a safe place (that can't be accessed from the web).
If you want to have a prompt like in one of the previous sections (different prompt for login in users and guests) then you can't use the login option because this will not allow using the terminal without login. Instead, you need to create a command that will call the login method.
$(function() {
$('#terminal').terminal({
hello: function() {
// client side only validation if token exists
// to protect the app you should validate
// the token on the server
if (this.get_token()) {
this.echo('Welcome');
} else {
this.error("You need to login first");
}
},
login: function() {
if (this.get_token()) {
this.error("you're already logged in");
} else {
this.login(function(user, password, callback) {
// this is just example in real applications check need to be on the server
// and token should be unique value generated on the server that you can
// be checked if it's valid by server
if (user === 'john' && password === 'connor') {
callback("SKYNET");
} else {
callback(null);
}
});
}
}
}, {
prompt: function(callback) {
if (this.get_token()) {
callback(this.login_name() + '@server$ ');
} else {
callback('guest@server$ ');
}
}
});
});
Here is alternative version using a nested interpreter (push
method) that you can exit from (with exit
command or with CTRL+D
):
$('body').terminal(function(command, term) {
var cmd = $.terminal.parse_command(command);
if (cmd.name === 'login') {
term.push({
hello: function() {
this.echo('hello there');
}
}, {
prompt: 'obi> ',
login: function(username, password) {
if (username === 'obi' && password === 'one') {
return Promise.resolve('TOKEN');
}
return Promise.reject();
}
});
} else {
this.error('Invalid Command.');
}
});
login method works the same as the login option. The callback is an old API that was not removed to not introduce breaking changes.
In every API that has a callback you can return a promise.
There is also an option to autologin if you get the token from somewhere else. Like from the other tab when using cross tab communication sysend library.
sysend.on('login', ({ user, token }) => {
term.autologin(user, token);
});
In version 2.37.0 with the introduction of the RPC interceptor (rpc
option), there is a way to create seamless JWT (access and refresh tokens). The code for the example (both browser and example PHP service) is located in php-terminal-jwt repository.
Library for Web-Based Terminal in JavaScript, (jQuery Terminal: git repo)
Copyright (c) 2011-2023 Jakub T. Jankiewicz