# -*- coding: utf-8 -*-## License: AGPLv3# This file is part of eduMFA. eduMFA is a fork of privacyIDEA which was forked from LinOTP.# Copyright (c) 2024 eduMFA Project-Team# Previous authors by privacyIDEA project:## 2015 - 2016 Cornelius Kölbel <cornelius.koelbel@netknights.it>## (c) 2015 Cornelius Kölbel - cornelius@privacyidea.org## This code is free software; you can redistribute it and/or# modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE# License as published by the Free Software Foundation; either# version 3 of the License, or any later version.## This code is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU AFFERO GENERAL PUBLIC LICENSE for more details.## You should have received a copy of the GNU Affero General Public# License along with this program. If not, see <http://www.gnu.org/licenses/>.#"""This file contains the definition of the paper token classIt depends on the DB model, and the lib.tokenclass."""importloggingfromedumfa.lib.logimportlog_withfromedumfa.lib.tokenclassimportTokenClassfromedumfa.lib.tokens.hotptokenimportHotpTokenClassfromedumfa.lib.policyimportSCOPE,ACTION,GROUPfromedumfa.libimport_log=logging.getLogger(__name__)DEFAULT_COUNT=100classPAPERACTION:PAPERTOKEN_COUNT="papertoken_count"
[docs]classPaperTokenClass(HotpTokenClass):""" The Paper Token allows to print out the next e.g. 100 OTP values. This sheet of paper can be used to authenticate and strike out the used OTP values. """# If the token is enrollable via multichallengeis_multichallenge_enrollable=False@log_with(log)def__init__(self,db_token):""" This creates a new Paper token object from a DB token object. :param db_token: instance of the orm db object :type db_token: orm object """TokenClass.__init__(self,db_token)self.set_type("paper")self.hKeyRequired=False
[docs]@staticmethoddefget_class_type():""" return the token type shortname :return: 'paper' :rtype: string """return"paper"
[docs]@staticmethoddefget_class_prefix():""" Return the prefix, that is used as a prefix for the serial numbers. :return: PPR """return"PPR"
[docs]@staticmethod@log_with(log)defget_class_info(key=None,ret='all'):""" returns a subtree of the token definition :param key: subsection identifier :type key: string :param ret: default return value, if nothing is found :type ret: user defined :return: subsection if key exists or user defined :rtype: dict or scalar """res={'type':'paper','title':'Paper Token','description':'PPR: One Time Passwords printed on a sheet ''of paper.','init':{},'config':{},'user':['enroll'],# This tokentype is enrollable in the UI for...'ui_enroll':["admin","user"],'policy':{SCOPE.ENROLL:{PAPERACTION.PAPERTOKEN_COUNT:{"type":"int","desc":_("The number of OTP values, which are ""printed on the paper.")},ACTION.MAXTOKENUSER:{'type':'int','desc':_("The user may only have this maximum number of paper tokens assigned."),'group':GROUP.TOKEN},ACTION.MAXACTIVETOKENUSER:{'type':'int','desc':_("The user may only have this maximum number of active paper tokens assigned."),'group':GROUP.TOKEN}}}}ifkey:ret=res.get(key,{})else:ifret=='all':ret=resreturnret
[docs]defupdate(self,param,reset_failcount=True):if"otpkey"notinparamand"verify"notinparam:param["genkey"]=1HotpTokenClass.update(self,param,reset_failcount=reset_failcount)papertoken_count=int(param.get("papertoken_count",DEFAULT_COUNT))# Now we calculate all the OTP values and add them to the# init_details. Thus, they will be returned by token/init.# But only if this is not in verify state.# TODO: check if can finish the request after verifying the token in the# prepolicy. Thus we would not need to go through all the token updatesif"verify"notinparam:otps=self.get_multi_otp(count=papertoken_count)self.add_init_details("otps",otps[2].get("otp",{}))