Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Table of Contents
web mvc framework for python
Package is uploaded on PyPI.
You can install it with pip:
$python3 pip install hallo
中文文档.
hallo --version
hallo create your-project
cd your-project
hallo install
file: module/hello.py
from app.module.base import BaseController
class HelloController(BaseController):
def world(self):
return 'hello world'
url: http://127.0.0.1/hello/world
file: module/json.py
from app.module.base import BaseController
class JsonController(BaseController):
def this_is_ok(self):
return self.ok('this is ok')
def this_is_error(self):
return self.error('this is error')
url: http://127.0.0.1/json/this-is-json
{
"code": 0,
"data": "this is ok",
}
url: http://127.0.0.1/json/this-is-error
{
"code": 1,
"data": "this is error",
}
file: module/html.py
from app.module.base import BaseController
class HtmlController(BaseController):
def index(self):
return self.render('html/index.html')
url: http://127.0.0.1/html/index
<p>hello world!</p>
file: models/user.py
from pymyorm.model import Model
class User(Model):
tablename = 'user'
run table/model to reflect all model from database
python console.py table/model
development
class DevelopmentConfig(Config):
ENV = 'development'
testing
class TestingConfig(Config):
ENV = 'testing'
production
class ProductionConfig(Config):
ENV = 'production'
host
class Config(object):
HOST = '127.0.0.1'
port
class Config(object):
PORT = 80
server name
class Config(object):
# domain
SERVER_NAME = 'hallo.com'
session
class Config(object):
# session
SECRET_KEY = ''
PERMANENT_SESSION_LIFETIME = timedelta(hours=1)
file upload
class Config(object):
# file upload
MAX_CONTENT_LENGTH = 8 * 1024 * 1024 # 8M
mysql
class Config(object):
# db: mysql / pgsql
DB_POOL_SIZE = 1
DB_CONF = dict(
source='mysql',
host='127.0.0.1',
port=3306,
user='root',
password='password',
database='hallo',
charset='utf8'
)
redis
class Config(object):
# redis
REDIS_URL = 'redis://127.0.0.1:6379/0'
memcache
class Config(object):
# cache
CACHE_CONF = [
'127.0.0.1:11211'
]
oss
class Config(object):
# oss
OSS_CONF = dict(
endpoint='',
bucket='',
access_key_id='',
access_key_secret=''
)
1、auto routing
http://127.0.0.1/<module>/<controller>/<action>
<module>: the directory or subdirectory under module
<controller>: the controller
<action>: the function of controller
2、user defined routing
file: app/router.py
router = Router(app=app)
router.add('/hello/<name>', 'hello/hi')
file: module/hello.py
from app.module.base import BaseController
class HelloController(BaseController):
def hi(self, name):
return f'hi, {name}'
url: http://127.0.0.1/hello/jack
hi, jack
3、subdomain
file: config.py
class Config(object):
SERVER_NAME = 'hallo.com'
file: app/router.py
admin = Router(app=app, subdomain='admin', module='admin')
1、get
file: module/http.py
from app.module.base import BaseController
class HttpController(BaseController):
def info(self):
name = self.get('name')
age = self.get('age')
return self.ok(dict(
name=name,
age=age
))
url: http://127.0.0.1/http/info?name=jack&age=18
{
"name": "jack",
"age": 18
}
2、post
file: module/http.py
from app.module.base import BaseController
class HttpController(BaseController):
def save(self):
name = self.post('name')
age = self.post('age')
return self.ok(dict(
name=name,
age=age
))
url: http://127.0.0.1/http/save
{
"name": "lucy",
"age": 18
}
3、header
file: module/header.py
from app.module.base import BaseController
class HeaderController(BaseController):
def token(self):
token = self.header('Token')
return self.ok(token)
url: http://127.0.0.1/header/token
{
"code": 0,
"data": {
"token": "123456"
}
}
4、file
file: module/file/upload.py
from app.module.base import BaseController
class FileController(BaseController):
def upload(self):
file = self.file('file')
url: http://127.0.0.1/file/upload
file: sql/user.sql
create table if not exists `user` (
`id` int unsigned not null auto_increment,
`username` varchar(32) not null default '',
`phone` varchar(16) not null default '',
`money` decimal(10,2) not null default 0,
`gender` tinyint unsigned not null default 0,
`password` varchar(128) not null default '',
`time` timestamp not null default current_timestamp,
primary key(`id`),
unique key `idx_username` (`username`),
key `idx_phone` (`phone`),
key `idx_time` (`time`)
) engine=InnoDB default charset=utf8mb4;
1、add user
file: module/user.py
from app.module.base import BaseController
from app.models.user import User
class UserController(BaseController):
def add(self):
username = self.post('username')
phone = self.post('phone')
money = self.post('money')
gender = self.post('gender')
model = User()
model.username = username
model.phone = phone
model.money = money
model.gender = gender
model.save()
return self.ok()
url: http://127.0.0.1/user/add
{
"code": 0,
"data": "ok"
}
2、edit user
file: module/user.py
from app.module.base import BaseController
from app.models.user import User
class UserController(BaseController):
def edit(self):
id = self.post('id')
username = self.post('username')
phone = self.post('phone')
money = self.post('money')
gender = self.post('gender')
model = User.find().where(id=id).one()
if not model:
return self.error('user not exists')
model.username = username
model.phone = phone
model.money = money
model.gender = gender
model.save()
return self.ok()
url: http://127.0.0.1/user/edit
{
"code": 0,
"data": "ok"
}
3、delete user
file: module/user.py
from app.module.base import BaseController
from app.models.user import User
class UserController(BaseController):
def delete(self):
id = self.post('id')
User.find().where(id=id).delete()
return self.ok()
url: http://127.0.0.1/user/delete
{
"code": 0,
"data": "ok"
}
4、list user
file: module/user.py
from app.module.base import BaseController
from app.models.user import User
class UserController(BaseController):
def list(self):
self.init_page()
model = User.find()
total = model.count()
all = model.offset(self.offset).limit(self.limit).all(raw=True)
return self.resp_page(all, total)
url: http://127.0.0.1/user/list
1、set
file: module/redis.py
from app.module.base import BaseController
class RedisController(BaseController):
def mem_set(self):
try:
key = self.get('key')
val = self.get('val')
self.redis.set(name=key, value=val, ex=3600)
return self.ok()
except Exception as e:
return self.error(str(e))
url: http://127.0.0.1/redis/mem-set?key=name&val=jack
2、get
file: module/redis.py
from app.module.base import BaseController
class RedisController(BaseController):
def mem_get(self):
try:
key = self.get('key')
val = self.redis.get(key)
if isinstance(val, bytes):
return self.ok(val.decode('UTF-8'))
else:
return self.error()
except Exception as e:
return self.error(str(e))
url: http://127.0.0.1/redis/mem-get?key=name
1、set
file: module/cache.py
from app.module.base import BaseController
class CacheController(BaseController):
def mem_set(self):
key = self.get('key')
val = self.get('val')
if self.cache.set(key, val):
return self.ok()
else:
return self.error()
url: http://127.0.0.1/cache/mem-set?key=name&val=lucy
2、get
file: module/cache.py
from app.module.base import BaseController
class CacheController(BaseController):
def mem_get(self):
key = self.get('key')
val = self.cache.get(key)
if val:
return self.ok(val)
else:
return self.error()
url: http://127.0.0.1/cache/mem-get?key=name
1、local
file: module/file.py
from app.module.base import BaseController
from app.helper.file import File
class FileController(BaseController):
def upload(self):
file = self.file('file')
f = File()
path = f.upload(file)
resp = dict()
resp['path'] = path
return self.ok(resp)
url: http://127.0.0.1/file/upload
{
"code": 0,
"data": {
"path": "static/upload/txt/9e/4e/9b/77/9e4e9b7754f8d4a26fc93663d2dae4d6.txt"
}
}
2、oss
file: module/oss.py
from app.module.base import BaseController
from app.helper.oss import Oss
class OssController(BaseController):
def upload(self):
file = self.file('file')
oss = Oss()
key = oss.upload(file)
resp = dict()
resp['key'] = key
resp['url'] = oss.url(key)
resp['sign_url'] = oss.sign_url(key=key, expires=3600)
return self.ok(resp)
url: http://127.0.0.1/oss/upload
file: module/html.py
from app.module.base import BaseController
class HtmlController(BaseController):
def index(self):
tv = dict()
tv['title'] = 'hello world!'
return self.render('html/index.html', tv)
url: http://127.0.0.1/html/index
1、builtin command: table
file: console/table.py
show all tables
python console.py table/show
create all tables
python console.py table/build
reflect all tables
python console.py table/model
2、builtin command: secret
file: console/secret.py
generate a random secret key
python console.py secret/key
3、user defined command: test
file: console/test.py
from app.console.base import BaseCommand
class TestCommand(BaseCommand):
def hello(self):
print('hello')
run test command
python console.py test/hello
1、app log
file: log/app.log
2022-07-04 22:12:13 INFO [base.py:28]: flask app init
2022-07-04 22:12:13 INFO [connection_pool.py:36]: put connection into pool
2022-07-04 22:12:13 INFO [_internal.py:224]: * Running on http://127.0.0.1:80 (Press CTRL+C to quit)
2、console log
file: log/console.log
2022-07-04 22:14:33 WARNING [table.py:27]: table user exists
log formatter
file: helper/functions.py
def create_log(log_file):
dictConfig({
'version': 1,
'formatters': {
'default': {
'format': '%(asctime)s %(levelname)s [%(filename)s:%(lineno)s]: %(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S'
}
},
'handlers': {
'wsgi': {
'class': 'logging.StreamHandler',
'stream': 'ext://flask.logging.wsgi_errors_stream',
'formatter': 'default'
},
'message': {
'class': 'logging.handlers.RotatingFileHandler',
'formatter': 'default',
'filename': log_file,
'maxBytes': 1024 * 1024,
'backupCount': 10,
'encoding': 'utf-8'
}
},
'root': {
'level': 'INFO',
'handlers': ['wsgi', 'message']
}
})
file: helper/decorator.py
1、time_cost
def time_cost(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
resp = func(*args, **kwargs)
end = time.time()
cost = round(end - start, 3)
logging.info(f'{request.path} time cost={cost}s')
return resp
return wrapper
2、retry
def retry(num=1, seconds=0):
def outer(func):
@functools.wraps(func)
def inner(*args, **kwargs):
for i in range(0, num):
try:
resp = func(*args, **kwargs)
if resp['code'] == 0:
return resp
if seconds > 0:
time.sleep(seconds)
except Exception as e:
logging.error(str(e))
return error(f'retry {num} times and failed')
return inner
return outer
3、check_login
def check_login(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
userid = session.get('userid')
if not userid:
return error('login is required', 401)
else:
return func(*args, **kwargs)
return wrapper
4、check_token
def check_token(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
token = request.headers.get('Token')
if not token:
return error('token is missing', 401)
if not app.config['redis'].get(token):
return error('token is expired', 401)
else:
return func(*args, **kwargs)
return wrapper
1、login by session
file: module/session/user.py
from app.module.base import BaseController
from flask import session
from app.models.user import User
from app.helper.decorator import check_login
class UserController(BaseController):
def login(self):
username = self.post('username')
password = self.post('password')
user = User.find().where(username=username).one()
if not user:
return self.error('user not exists')
if user.password != password:
return self.error('wrong password')
session['userid'] = user.id
return self.ok('login success')
2、logout by session
file: module/session/user.py
from app.module.base import BaseController
from flask import session
from app.models.user import User
from app.helper.decorator import check_login
class UserController(BaseController):
@check_login
def logout(self):
session.pop('userid')
return self.ok('logout success')
3、login by token
file: module/token/user.py
from app.module.base import BaseController
from app.module.user import User
from app.helper.decorator import check_token
class UserController(BaseController):
def login(self):
username = self.post('username')
password = self.post('password')
user = User.find().where(username=username).one()
if not user:
return self.error('user not exists')
if user.password != password:
return self.error('wrong password')
token = user.login()
resp = dict()
resp['token'] = token
return self.ok(resp)
4、logout by token
file: module/token/user.py
from app.module.base import BaseController
from app.module.user import User
from app.helper.decorator import check_token
class UserController(BaseController):
@check_token
def logout(self):
self.user.logout()
return self.ok('logout success')
cd your-project
hallo install
./install.sh
start project
./supervisor/start.sh
stop project
./supervisor/stop.sh
restart project
./supervisor/restart.sh
shutdown project
./supervisor/shutdown.sh
Hallo is released under the MIT License. See LICENSE for more information.
FAQs
web mvc framework for python
We found that Hallo demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.