Exemple #1
0
async def authenticate(info: RModels.Authserver_Authenticate):
    user: Account = Account.get(Email=info.username)
    if not user:
        raise exceptions.InvalidCredentials()

    if not user_auth_cooling_bucket.get(user.Email):
        user_auth_cooling_bucket.setByTimedelta(user.Email, "LOCKED")
    else:
        raise exceptions.InvalidCredentials()

    if not bcrypt.checkpw(info.password.encode(), user.Password):
        raise (exceptions.InvalidCredentials())
 
    TokenUnit = Token(user, ClientToken=info.clientToken)
    auth_token_pool.setByTimedelta(TokenUnit.AccessToken, TokenUnit)
    result = {
        "accessToken": TokenUnit.AccessToken.hex,
        "clientToken": TokenUnit.ClientToken,
        "availableProfiles": [
            i.FormatCharacter(unsigned=True) for i in list(user.Characters)
        ],
        "selectedProfile": {}
    }
    # print(data.get("clientToken"), TokenUnit.ClientToken)
    if user.Characters.count() == 1:  # 如果只拥有一个角色, 则自动绑定, 并修改result
        TokenUnit.setupCharacter(list(user.Characters)[0])
        result['selectedProfile'] = list(user.Characters)[0].FormatCharacter(unsigned=True)
    else:
        del result['selectedProfile']
    if info.requestUser:
        result['user'] = {
            "id": user.Id.hex,
            "properties": []
        }
    return Response(result)
async def resources_account(accountId: uuid.UUID,
                            optionalAccount: Optional[Account] = Depends(
                                depends.O_N_Owen)):
    with orm.db_session:
        account: Account = Account.get(Id=accountId)
        if not account:
            raise exceptions.NoSuchResourceException()

        return {
            "accountId": account.Id,
            "email": "".join([account.Email[0:3], "*" * (len(account.Email) - 6), account.Email[-3:]]),
            "username": account.AccountName,
            "characters": [
                {
                    "characterId": i.Id,
                    "player": {
                        "id": i.PlayerId,
                        "name": i.PlayerName
                    }
                } for i in account.Characters if i.Public
            ],
            "resources": [
                {
                    "id": i.Id,
                    "name": i.Name,
                    "createAt": i.CreatedAt,
                    "metadata": {
                        "type": i.Type,
                        "model": i.Model
                    }
                } for i in account.OwnedResources if not i.IsPrivate or\
                    accountId == (optionalAccount.Id if optionalAccount else None)
            ]
        }
Exemple #3
0
async def mostima_register_request(register_info: MostimaRegister, request: Request):
    attempt_assert_occupy = Account.get(Email=register_info.email)
    if attempt_assert_occupy:
        raise exceptions.OccupyExistedAddress({
            "accountId": attempt_assert_occupy.Id
        })
    # 尝试断言: 有无Email相同账号

    # 断言被跳过, 无Email相同账号
    if not MostimaBuckets.requestLimit.get(register_info.email):
        MostimaBuckets.requestLimit.setByTimedelta(register_info.email, "LOCKED", delta={
            "seconds": 60
        })
    else:
        raise exceptions.FrequencyLimit({
            "email": register_info.email
        })

    # 生成verifyId
    verifyId = String(config['natrium']['mostima']['request']['verifyId-length'])
    salt = bcrypt.gensalt()

    requests_bucket: AioCacheBucket = MostimaBuckets.requests
    
    try:
        emailer.send_mail(register_info.email, {
            'subject': Ts_("mostima.mail_content.subject"),
            "content_text": Ts_("mostima.mail_content.content_text")\
                .format(verify_url=urlunparse(
                    ParseResult(
                        scheme=request.url.scheme,
                        netloc=request.url.netloc,
                        path="/natrium/mostima/register/request/verify",
                        params="",
                        query=urlencode({
                            "verifyId": verifyId
                        }),
                        fragment=""
                    )
                ))
        })
        requests_bucket.setByTimedelta(verifyId, {
            "email": register_info.email,
            "name": register_info.accountName,
            "password": bcrypt.hashpw(register_info.password.encode(), salt),
            "salt": salt,
            "redirectTo": register_info.redirectTo
        })
    except Exception as e:
        print(e)
        return selected_jsonencoder(
            MostimaRequest_Response(operator="failed").dict(), 
            status_code=500
        )
    return MostimaRequest_Response(operator="success")
Exemple #4
0
async def signout(info: RModels.Authserver_Signout):
    user: Account = Account.get(Email=info.username)
    if not user:
        raise exceptions.InvalidCredentials()

    if not user_auth_cooling_bucket.get(user.Email):
        user_auth_cooling_bucket.setByTimedelta(user.Email, "LOCKED")
    else:
        raise exceptions.InvalidCredentials()

    if not bcrypt.checkpw(info.password.encode("utf-8"), user.Password):
        raise exceptions.InvalidCredentials()
    for i in Token.getManyTokens(user):
        auth_token_pool.delete(i.AccessToken)
    return Response(status_code=204)
Exemple #5
0
async def authserver_signout(authinfo: AccountAuth):
    account = Account.get(Email=authinfo.email)
    if not account:
        raise exceptions.InvalidCredentials()

    if not VerifyLocks.get(account.Id):
        VerifyLocks.setByTimedelta(account.Id, "LOCKED")
    else:
        raise exceptions.FrequencyLimit()

    AuthentidcateVerifyResult = bcrypt.checkpw(authinfo.password.encode(),
                                               account.Password)
    if not AuthentidcateVerifyResult:
        raise exceptions.InvalidCredentials()

    for i in TokenBucket:
        if TokenBucket.get(i).Account.Id == account.Id:
            TokenBucket.delete(i)
    return {"operator": "success"}
Exemple #6
0
async def os_char_create(createInfo: models.CharacterCreate,
                         account: Account = Depends(
                             depends.AccountFromRequest)):
    if not res.verify(createInfo.create.name, res.CharacterName):
        raise exceptions.NonCompliantMsg()

    if Character.get(PlayerName=createInfo.create.name):
        raise exceptions.OccupyExistedAddress()

    account = Account.get(Id=account.Id)

    character = Character(PlayerId=OfflinePlayerUUID(createInfo.create.name),
                          PlayerName=createInfo.create.name,
                          Owner=account,
                          CreatedAt=dt.now(),
                          UpdatedAt=dt.now(),
                          Public=createInfo.create.public)

    orm.commit()
    return character.format_self()
Exemple #7
0
async def mostima_register_request_verify(verifyId: str, request: Request):
    verify_result = requests_bucket.get(verifyId)
    if not verify_result:
        raise exceptions.BrokenData({
            "position": "query_params.verifyId"
        })
    result = Account(
        Email=verify_result['email'],
        AccountName=verify_result['name'],
        Password=verify_result['password'],
        Salt=verify_result['salt']
    )
    orm.commit()
    if verify_result['redirectTo']:
        redirect: ParseResult = urlparse(verify_result['redirectTo'])
        redirect.query = urlencode({
            "accountId": result.Id
        })
        return RedirectResponse(urlunparse(redirect), status_code=302)
    return {
        "id": result.Id
    }
Exemple #8
0
async def authserver_authenticate(authinfo: AuthenticateRequest):
    account = Account.get(Email=authinfo.email)
    if not account:
        raise exceptions.InvalidCredentials()

    if not VerifyLocks.get(account.Id):
        VerifyLocks.setByTimedelta(account.Id, "LOCKED")
    else:
        raise exceptions.FrequencyLimit()

    AuthentidcateVerifyResult = bcrypt.checkpw(authinfo.password.encode(),
                                               account.Password)
    if not AuthentidcateVerifyResult:
        raise exceptions.InvalidCredentials()

    token = Token(account, authinfo.authenticate.clientToken)
    TokenBucket.setByTimedelta(token.AccessToken, token)

    result = {
        "auth": {
            "accessToken": token.AccessToken.hex,
            "clientToken": token.ClientToken,
            "metadata": {
                "stages": {
                    "create": token.CreateAt.rfc2822(),
                    "alive": token.AliveDate.rfc2822(),
                    "expire": token.ExpireDate.rfc2822(),
                }
            }
        }
    }
    if authinfo.requestAccount:
        result['account'] = {
            "id": account.Id.hex,
            "email": account.Email,
            "createAt": maya.MayaDT(account.CreatedAt.timestamp()).rfc2822(),
            "rank": account.Permission
        }
    return result
Exemple #9
0
async def amadeus_upload(
        bgTasks: BackgroundTasks,

        file: UploadFile = File(...),
        name: str = Query(..., min_length=4, max_length=60, regex=res.ResourceName),

        Model: enums.MCTextureModel = Query("auto", alias="model"),
        Type: enums.MCTextureType = Query(..., alias="type"),
        
        Private: bool = False,
        Protect: bool = False,

        uploader: Account = Depends(depends.AccountFromRequestForm(alias="auth"))
    ):
    """参数name为要创建的资源名称.\n 
    通过表单API上传图片, 名称"file"\n
    通过表单发送认证, 名称"auth".\n

    可用get query传参: \n
    
    ``` url
    http://127.0.0.1:8000/natrium/amadeus/upload/aResourceName?type=skin&strict=true&model=alex
    ```
    """
    # 常量分配
    Original: bool = True # 在库中是否是第一个被创建的
    OriginalResource: Optional[Resource] = None
    OriginalUploader: Optional[Account] = None

    if Private and Protect:
        raise exceptions.DuplicateRegulations()

    try:
        image: Image.Image = Image.open(BytesIO(await file.read()))
    except PIL.UnidentifiedImageError:
        raise exceptions.NonCompliantMsg({
            "filename": file.filename
        })
    finally:
        await file.close()

    width, height = image.size

    if image.format != "PNG":
        raise exceptions.NonCompliantMsg({
            "image.format": {
                "value": image.format,
                "assert": "PNG"
            }
        })

    if height > config['natrium']['upload']['picture-size']['height'] or\
        width > config['natrium']['upload']['picture-size']['width']:
        raise exceptions.NonCompliantMsg()

    image.resize((
        int(width / 22) * 32 if width % 22 == 0 else width,
        int(width / 17) * 32 if height % 17 == 0 else height
    ))

    pictureContentHash = hashing.PicHash(image)

    attempt_select = orm.select(i for i in Resource if i.PicHash == pictureContentHash)
    if attempt_select.exists():
        # 如果真的有上传的数据一样的
        Original = False
        for i in attempt_select[:]:
            # 询问数据库, 找到原始作者
            # 考虑加入uploader找寻.
            if not i.Origin:
                OriginalResource = i
                OriginalUploader = i.Owner
                break

        if not OriginalResource or\
            not OriginalUploader: # 判断是否找到了, 如果没找到, 说明数据库信息受损
            raise exceptions.BrokenData({
                "PictureHash": pictureContentHash,
                "ExceptionRaisedTime": maya.now()
            })

        # 如果有attempt_select, 就一定有一个origin.
        # 判断是否是原作者闲着没事干, 重新上传了一个.
        if OriginalUploader.Id == uploader.Id:
            raise exceptions.OccupyExistedAddress({
                "originalResource": {
                    "id": OriginalResource.Id,
                    "owner": OriginalUploader.Id
                },
                "uploader": {
                    "id": uploader.Id
                }
            })
        else: # ...或者是其他人, 这种情况我们需要特殊处理
            # 由于Protect的受限度较低, 故放在上面点.
            if OriginalResource.Protect:
                if Protect or Private:
                    raise exceptions.PermissionDenied({
                        "originalResource": {
                            "id": OriginalResource.Id,
                            "owner": OriginalUploader.Id,
                            "protect": OriginalResource.Protect,
                            "private": OriginalResource.Private
                        },
                        "uploader": {
                            "id": uploader.Id
                        }
                    })
                else: # 但是你本来就可以设为这个啊, 为啥要自己整一路去?
                    raise exceptions.OccupyExistedAddress({
                        "originalResource": {
                            "id": OriginalResource.Id,
                            "owner": OriginalUploader.Id,
                            "protect": OriginalResource.Protect,
                        },
                        "uploader": {
                            "id": uploader.Id
                        }
                    })
            elif OriginalResource.IsPrivate:
                # 如果私有, 则不允许任何人上传/使用/设保护/私有等
                raise exceptions.OccupyExistedAddress({
                    "originalResource": {
                        "id": OriginalResource.Id,
                        "owner": OriginalUploader.Id,
                        "protect": OriginalResource.Protect,
                    },
                    "uploader": {
                        "id": uploader.Id
                    }
                })
            else:
                # 你什么私有保护什么的都没开? 别开你自己的私有保护什么的就OK.
                if Protect or Private:
                    raise exceptions.PermissionDenied({
                        "originalResource": {
                            "id": OriginalResource.Id,
                            "owner": OriginalUploader.Id
                        },
                        "uploader": {
                            "id": uploader.Id
                        },
                        "options": {
                            'protect': Protect,
                            "private": Private
                        }
                    })
                else:
                    # 找寻上传者是否也曾经上传过该材质
                    assert_the_same = orm.select(i for i in Resource\
                        if i.PicHash == pictureContentHash and \
                        i.Owner.Id == uploader.Id)
                    if assert_the_same.exists():
                        ats_first: Resource = assert_the_same.first()
                        raise exceptions.OccupyExistedAddress({
                            "ownedResource": {
                                "id": ats_first.Id,
                                "name": ats_first.Name
                            },
                            "uploader": {
                                "id": uploader.Id
                            }
                        })

        if Model == "auto":
            Model = ['steve', 'alex'][skin.isSilmSkin(image)]

        account = Account.get(Id=uploader.Id)
        resource = Resource(
            PicHash = pictureContentHash,
            Name = name,
            PicHeight = height, PicWidth = width,
            Model = Model, Type = Type,
            Owner = account,
            IsPrivate = Private, Protect = Protect,
            Origin = OriginalResource
        )
        if Original:
            bgTasks.add_task(Save, image, pictureContentHash)
        orm.commit()
        return {
            "operator": "success",
            "metadata": resource.format_self(requestHash=True)
        }