feat: add cookie for site token

This commit is contained in:
KernelDeimos
2024-06-19 00:51:16 -04:00
committed by Eric Dubé
parent 86fca17fb1
commit a813fbbb88
3 changed files with 122 additions and 38 deletions
@@ -153,41 +153,100 @@ class PuterSiteMiddleware extends AdvancedBase {
if ( site.protected ) {
const svc_auth = req.services.get('auth');
const token = req.query['puter.auth.token'];
const get_site_actor_from_token = async () => {
const site_token = req.cookies['puter.site.token'];
if ( ! site_token ) return;
acl_config.no_acl = false;
if ( ! token ) {
const e = APIError.create('token_missing');
return this.respond_error_({ req, res, e });
}
const app_actor =
await svc_auth.authenticate_from_token(token);
const user_actor =
app_actor.get_related_actor(UserActorType);
const svc_permission = req.services.get('permission');
const perm = await (async () => {
if ( user_actor.type.user.id === site.user_id ) {
return {};
let failed = false;
let site_actor;
try {
site_actor =
await svc_auth.authenticate_from_token(site_token);
} catch (e) {
failed = true;
}
if ( failed ) return;
return await svc_permission.check(
user_actor, `site:uid#${site.uuid}:access`
);
})();
if ( ! site_actor ) return;
// security measure: if 'puter.site.token' is set
// to a different actor type, someone is likely
// trying to exploit the system.
if ( ! (site_actor.type instanceof SiteActorType) ) {
return;
}
acl_config.actor = site_actor;
// Refresh the token if it's been 30 seconds since
// the last request
if (
(Date.now() - site_actor.type.iat*1000)
>
1000*30
) {
const site_token = svc_auth.get_site_app_token({
site_uid: site.uuid,
});
res.cookie('puter.site.token', site_token);
}
return true;
};
if ( ! perm ) {
const e = APIError.create('forbidden');
return this.respond_error_({ req, res, e });
const make_site_actor_from_app_token = async () => {
const token = req.query['puter.auth.token'];
acl_config.no_acl = false;
if ( ! token ) {
const e = APIError.create('token_missing');
return this.respond_error_({ req, res, e });
}
const app_actor =
await svc_auth.authenticate_from_token(token);
const user_actor =
app_actor.get_related_actor(UserActorType);
const svc_permission = req.services.get('permission');
const perm = await (async () => {
if ( user_actor.type.user.id === site.user_id ) {
return {};
}
return await svc_permission.check(
user_actor, `site:uid#${site.uuid}:access`
);
})();
if ( ! perm ) {
const e = APIError.create('forbidden');
this.respond_error_({ req, res, e });
return false;
}
const site_actor = await Actor.create(SiteActorType, { site });
acl_config.actor = site_actor;
// This subdomain is allowed to keep the site actor token,
// so we send it here as a cookie so other html files can
// also load.
const site_token = svc_auth.get_site_app_token({
site_uid: site.uuid,
});
res.cookie('puter.site.token', site_token);
return true;
}
const site_actor = await Actor.create(SiteActorType, { site });
acl_config.actor = site_actor;
console.log('THE SITE ACTOR?', site_actor);
let ok = await get_site_actor_from_token();
if ( ! ok ) {
ok = await make_site_actor_from_app_token();
}
if ( ! ok ) return;
Object.freeze(acl_config);
}
@@ -103,14 +103,14 @@ class PuterSiteService extends BaseService {
return rows[0];
}
// async get_subdomain_by_uid (uid) {
// const rows = await this.db.read(
// `SELECT * FROM subdomains WHERE uuid = ? LIMIT 1`,
// [uid]
// );
// if ( rows.length === 0 ) return null;
// return rows[0];
// }
async get_subdomain_by_uid (uid) {
const rows = await this.db.read(
`SELECT * FROM subdomains WHERE uuid = ? LIMIT 1`,
[uid]
);
if ( rows.length === 0 ) return null;
return rows[0];
}
}
module.exports = {
@@ -16,7 +16,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { Actor, UserActorType, AppUnderUserActorType, AccessTokenActorType } = require("./Actor");
const { Actor, UserActorType, AppUnderUserActorType, AccessTokenActorType, SiteActorType } = require("./Actor");
const BaseService = require("../BaseService");
const { get_user, get_app } = require("../../helpers");
const { Context } = require("../../util/context");
@@ -130,6 +130,17 @@ class AuthService extends BaseService {
type: actor_type,
});
}
if ( decoded.type === 'actor-site' ) {
const site_uid = decoded.site_uid;
const svc_puterSite = this.services.get('puter-site');
const site =
await svc_puterSite.get_subdomain_by_uid(site_uid);
return Actor.create(SiteActorType, {
site,
iat: decoded.iat,
});
}
throw APIError.create('token_auth_failed');
}
@@ -159,6 +170,20 @@ class AuthService extends BaseService {
return token;
}
get_site_app_token ({ site_uid }) {
const token = this.modules.jwt.sign(
{
type: 'actor-site',
version: '0.0.0',
site_uid,
},
this.global_config.jwt_secret,
{ expiresIn: '1h' },
);
return token;
}
async create_session_ (user, meta = {}) {
this.log.info(`CREATING SESSION`);