wip: initial commit

This commit is contained in:
ptrcnull 2023-06-16 20:59:10 +02:00
commit 26efd8e1a7
7 changed files with 222 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
build/
dist/
*.egg-info
__pycache__/

9
LICENCE Normal file
View file

@ -0,0 +1,9 @@
Copyright (c) <year> <owner>
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

8
README.md Normal file
View file

@ -0,0 +1,8 @@
# kakushi
> an implementation of [Freedesktop's Secrets API][1] for [himitsu][2]
> [kakushi (隠し) - being hidden; being concealed][3]
[1]: https://freedesktop.org/wiki/Specifications/secret-storage-spec/secrets-api-0.1.html
[2]: https://himitsustore.org/
[3]: https://jisho.org/word/%E9%9A%A0%E3%81%97

42
kakushi/himitsu.py Normal file
View file

@ -0,0 +1,42 @@
import socket
import os
import os.path
import typing
class Client:
def __init__(self, addr = None):
if not addr:
addr = os.path.join(os.getenv('XDG_RUNTIME_DIR'), 'himitsu')
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self.sock.connect(addr)
def query(self, **kwargs):
return self._query(kwargs)
def query_decrypt(self, **kwargs):
return self._query(kwargs, True)
def _query(self, query: typing.Dict[str, str], decrypt: bool = False):
params = ['query']
if decrypt:
params.append('-d')
for arg in query:
params.append(f'{arg}={query[arg]}')
qs = ' '.join(params) + '\n'
self.sock.send(qs.encode('utf-8'))
raw_res = self._read_raw_response()
return raw_res
def _read_raw_response(self):
res = ''
while not '\nend\n' in res:
res += self.sock.recv(4096).decode('utf-8')
res = res.strip()
res_lines = res.splitlines()
res_lines.pop()
return res_lines

133
kakushi/main.py Normal file
View file

@ -0,0 +1,133 @@
from pydbus import SessionBus
from pydbus.generic import signal
from gi.repository import GLib
import himitsu
loop = GLib.MainLoop()
bus = SessionBus()
hiq = himitsu.Client()
class Collection(object):
'''
<node>
<interface name="org.freedesktop.Secret.Collection">
<property name="Items" type="ao" access="read" />
<property name="Private" type="s" access="read" />
<property name="Label" type="s" access="readwrite" />
<property name="Locked" type="b" access="read" />
<property name="Created" type="t" access="read" />
<property name="Modified" type="t" access="read" />
<method name="Delete">
<arg name="prompt" type="o" direction="out" />
</method>
<method name="SearchItems">
<arg name="attributes" type="a{ss}" direction="in" />
<arg name="results" type="ao" direction="out" />
</method>
<method name="CreateItem">
<arg name="properties" type="a{sv}" direction="in" />
<arg name="secret" type="(sayay)" direction="in" />
<arg name="replace" type="b" direction="in" />
<arg name="item" type="o" direction="out" />
<arg name="prompt" type="o" direction="out" />
</method>
<signal name="ItemCreated">
<arg name="item" type="o" />
</signal>
<signal name="ItemDeleted">
<arg name="item" type="o" />
</signal>
</interface>
</node>
'''
@property
def Items(self):
return []
Label = 'default'
Private = 'yes?'
Locked = False
Created = 0
Modified = 0
ItemCreated = signal()
ItemDeleted = signal()
class Service(object):
'''
<node>
<interface name="org.freedesktop.Secret.Service">
<property name="Collections" type="ao" access="read" />
<property name="DefaultCollection" type="o" access="readwrite" />
<method name="OpenSession">
<arg name="result" type="o" direction="out" />
</method>
<method name="CreateCollection">
<arg name="label" type="s" direction="in" />
<arg name="private" type="b" direction="in" />
</method>
<method name="LockService" />
<method name="SearchCollections">
<arg name="fields" type="a{ss}" direction="in" />
<arg name="results" type="ao" direction="out" />
<arg name="locked" type="ao" direction="out" />
</method>
<method name="RetrieveSecrets">
<arg name="items" type='as' direction='in' />
<arg name="secrets" type='ao' direction='out' />
</method>
<signal name="CollectionCreated">
<arg name="collection" type="o" />
</signal>
<signal name="CollectionDeleted">
<arg name="collection" type="o" />
</signal>
</interface>
</node>
'''
sessions = []
def OpenSession(self):
print('OpenSession')
pass
def LockService(self):
pass
def SearchCollections(self, fields):
print('SearchCollections', fields)
return ([], [])
@property
def Collections(self):
return ['/org/freedesktop/secrets/collection/default']
DefaultCollection = '/org/freedesktop/secrets/collection/default'
CollectionCreated = signal()
CollectionDeleted = signal()
CollectionChanged = signal()
def entrypoint():
bus.publish(
"org.freedesktop.secrets", Service(),
('collection/default', Collection())
)
loop.run()
if __name__ == '__main__':
entrypoint()

23
pyproject.toml Normal file
View file

@ -0,0 +1,23 @@
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[project]
name = "kakushi"
version = "0.1.0"
authors = [
{name = "Patrycja Rosa", email = "foss@ptrcnull.me"},
]
description = "an implementation of Secrets API for himitsu"
readme = "README.md"
requires-python = ">=3.7"
license = {text = "BSD-2-Clause"}
classifiers = [
"Programming Language :: Python :: 3",
]
dependencies = [
"pydbus >= 0.6"
]
[project.scripts]
kakushi = "kakushi.main:entrypoint"

3
setup.py Normal file
View file

@ -0,0 +1,3 @@
from setuptools import setup
setup()