mirror of
https://github.com/jamesstringer90/appsandbox.git
synced 2026-10-22 11:03:15 -05:00
122 lines
4.4 KiB
JavaScript
122 lines
4.4 KiB
JavaScript
import Gio from 'gi://Gio';
|
|
import GLib from 'gi://GLib';
|
|
import Mtk from 'gi://Mtk';
|
|
import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
|
|
|
|
export default class AppSandboxPointer extends Extension {
|
|
enable() {
|
|
this._uid = new Gio.Credentials().get_unix_user();
|
|
const path = GLib.build_filenamev([
|
|
GLib.get_user_runtime_dir(), 'appsandbox-pointer.sock',
|
|
]);
|
|
const file = Gio.File.new_for_path(path);
|
|
let info;
|
|
try {
|
|
info = file.query_info('unix::uid,unix::mode',
|
|
Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
|
|
} catch (error) {
|
|
if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
|
|
throw error;
|
|
}
|
|
if (info) {
|
|
if (info.get_attribute_uint32('unix::uid') !== this._uid ||
|
|
(info.get_attribute_uint32('unix::mode') & 0o170000) !== 0o140000)
|
|
throw new Error('Invalid AppSandbox pointer socket');
|
|
file.delete(null);
|
|
}
|
|
|
|
this._service = new Gio.SocketService({active: false});
|
|
try {
|
|
this._service.add_address(Gio.UnixSocketAddress.new(path),
|
|
Gio.SocketType.STREAM, Gio.SocketProtocol.DEFAULT, null);
|
|
this._socketFile = file;
|
|
file.set_attribute_uint32('unix::mode', 0o600,
|
|
Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
|
|
this._incoming = this._service.connect('incoming',
|
|
(_service, connection) => this._accept(connection));
|
|
this._service.start();
|
|
} catch (error) {
|
|
this.disable();
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
disable() {
|
|
if (this._service) {
|
|
if (this._incoming)
|
|
this._service.disconnect(this._incoming);
|
|
this._service.stop();
|
|
this._service.close();
|
|
this._service = null;
|
|
this._incoming = 0;
|
|
}
|
|
if (this._socketFile) {
|
|
try {
|
|
this._socketFile.delete(null);
|
|
} catch (_) {
|
|
}
|
|
this._socketFile = null;
|
|
}
|
|
}
|
|
|
|
_getPosition() {
|
|
const unavailable = [-2147483648, -2147483648, 0, 0];
|
|
try {
|
|
const views = global.stage.peek_stage_views();
|
|
if (views.length !== 1)
|
|
return unavailable;
|
|
const view = views[0];
|
|
if (view.get_transform() !== Mtk.MonitorTransform.NORMAL)
|
|
return unavailable;
|
|
const framebuffer = view.get_onscreen();
|
|
if (!framebuffer)
|
|
return unavailable;
|
|
const width = framebuffer.get_width();
|
|
const height = framebuffer.get_height();
|
|
const scale = view.get_scale();
|
|
const layout = view.layout;
|
|
const [point] = global.backend.get_cursor_tracker().get_pointer();
|
|
if (!(width > 0 && height > 0 && Number.isFinite(scale) && scale > 0) ||
|
|
!Number.isFinite(point.x) || !Number.isFinite(point.y))
|
|
return unavailable;
|
|
const x = Math.trunc((point.x - layout.x) * scale);
|
|
const y = Math.trunc((point.y - layout.y) * scale);
|
|
return [Math.max(0, Math.min(width - 1, x)),
|
|
Math.max(0, Math.min(height - 1, y)), width, height];
|
|
} catch (_) {
|
|
return unavailable;
|
|
}
|
|
}
|
|
|
|
_accept(connection) {
|
|
try {
|
|
if (!this._service)
|
|
return true;
|
|
const socket = connection.get_socket();
|
|
const uid = socket.get_credentials().get_unix_user();
|
|
if (uid !== 0 && uid !== this._uid)
|
|
return true;
|
|
const position = this._getPosition();
|
|
const reply = new Uint8Array(16);
|
|
const data = new DataView(reply.buffer);
|
|
for (let i = 0; i < position.length; i++)
|
|
data.setInt32(i * 4, position[i], true);
|
|
socket.set_blocking(false);
|
|
let offset = 0;
|
|
while (offset < reply.length) {
|
|
const written = socket.send(reply.subarray(offset), null);
|
|
if (written <= 0)
|
|
break;
|
|
offset += written;
|
|
}
|
|
} catch (_) {
|
|
} finally {
|
|
try {
|
|
connection.close(null);
|
|
} catch (_) {
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|