Plateforme Level Extreme
Abonnement
Profil corporatif
Produits & Services
Support
Légal
English
Checking Password Format
Message
 
À
29/05/2014 16:14:15
Information générale
Forum:
Visual FoxPro
Catégorie:
Autre
Versions des environnements
Visual FoxPro:
VFP 7
OS:
Windows Server 2012
Network:
Windows 2008 Server
Database:
Visual FoxPro
Application:
Desktop
Divers
Thread ID:
01600934
Message ID:
01600951
Vues:
61
>All,
>
>I would like have my users to create their passwords in the following format:
>
>
>
>How do I check to see if their passwords meet the criteria once they create and/or change their passwords?
>
>•be at least 10 characters
>•contain at least 2 special characters: ! @ # $ % ^ & * _ - + = ' : ; . ,
>•contain at least 2 numbers
>•contain at least 2 uppercase and 2 lowercase letters
>•not be an old password


I wrote a program millennial ago to deal with similar rules (not quite the same, but it can give you an idea) , now, this was a part of a bigger application and furthermore it had code scattered in our class libraries, I tried to remove all that I could, but it takes a long time to do it, and as I said, I wrote this code long time ago, so I do not remember much and probably is not that good either...

The code has 3 parts, a form where you can enter an validate the password, a password manager class to create random passwords and where the validations rules are performed, and a support class for generating random stuff

Form: (The space on top are things I removed also some buttons I left to give you an idea, but the code for Encrypting the passwords and some keys are not included so it won't work)
PUBLIC ofrmpasswordmanager

ofrmpasswordmanager=NEWOBJECT("frmpasswordmanager")
ofrmpasswordmanager.Show
RETURN

*#INCLUDE "\\skyapps\apps\foxv\classes\encrypt.h"
*
DEFINE CLASS frmpasswordmanager AS form


	Height = 546
	Width = 574
	DoCreate = .T.
	BorderStyle = 3
	Caption = "Password Manager"
	passwordgenerator = .NULL.
	currentpasswordpk = .NULL.
	lastpasswordpk = .NULL.
	help_id = 2008-01403
	oldlibraries = ""
	Name = "frmPasswordManager"

	ADD OBJECT shape1 AS shape WITH ;
		Top = 146, ;
		Left = 1, ;
		Height = 363, ;
		Width = 572, ;
		BorderStyle = 0, ;
		FillStyle = 0, ;
		FillColor = RGB(255,219,183), ;
		ZOrderSet = 0, ;
		Name = "shape1"


	ADD OBJECT txtcurrentpassword AS textbox WITH ;
		FontName = "Consolas", ;
		FontSize = 12, ;
		Height = 23, ;
		Left = 119, ;
		Margin = 0, ;
		ReadOnly = .T., ;
		Top = 30, ;
		Width = 367, ;
		ForeColor = RGB(255,0,128), ;
		ZOrderSet = 7, ;
		Name = "txtCurrentPassword"


	ADD OBJECT lblnewpassword AS label WITH ;
		Caption = "New Password", ;
		Left = 1, ;
		Top = 172, ;
		ZOrderSet = 8, ;
		Name = "lblNewPassword"


	ADD OBJECT txtnewpassword AS textbox WITH ;
		FontName = "Consolas", ;
		FontSize = 12, ;
		Format = "T", ;
		Height = 23, ;
		Left = 119, ;
		Margin = 0, ;
		Top = 169, ;
		Width = 367, ;
		ZOrderSet = 9, ;
		Themes = .F., ;
		Name = "txtNewPassword"


	ADD OBJECT cmdgenerate AS commandbutton WITH ;
		Top = 147, ;
		Left = 1, ;
		Height = 23, ;
		Width = 117, ;
		FontName = "Arial Narrow", ;
		FontSize = 10, ;
		Caption = "New random password", ;
		ZOrderSet = 10, ;
		Name = "cmdGenerate"


	ADD OBJECT ctrchecklist AS ctrCheckListClass WITH ;
		Top = 200, ;
		Left = 119, ;
		Width = 367, ;
		Height = 307, ;
		SpecialEffect = 0, ;
		ZOrderSet = 11, ;
		Name = "ctrCheckList"




	ADD OBJECT commandbutton1 AS commandbutton WITH ;
		Top = 30, ;
		Left = 488, ;
		Height = 23, ;
		Width = 84, ;
		Caption = "To Clipboard", ;
		ZOrderSet = 12, ;
		Name = "commandbutton1"


	ADD OBJECT label3 AS label WITH ;
		Caption = "Validity Checklist", ;
		Left = 1, ;
		Top = 202, ;
		ZOrderSet = 13, ;
		Name = "label3"


	ADD OBJECT txtlastpasswordused AS textbox WITH ;
		FontName = "Consolas", ;
		FontSize = 12, ;
		Height = 23, ;
		Left = 119, ;
		Margin = 0, ;
		ReadOnly = .T., ;
		Top = 2, ;
		Width = 367, ;
		ForeColor = RGB(0,0,255), ;
		ZOrderSet = 14, ;
		Name = "txtLastPasswordUsed"


	ADD OBJECT commandbutton2 AS commandbutton WITH ;
		Top = 2, ;
		Left = 488, ;
		Height = 23, ;
		Width = 84, ;
		Caption = "To Clipboard", ;
		ZOrderSet = 15, ;
		Name = "commandbutton2"


	ADD OBJECT lbllastpasswordused AS label WITH ;
		Caption = "Last Password Used", ;
		Left = 1, ;
		Top = 5, ;
		ForeColor = RGB(0,0,255), ;
		ZOrderSet = 16, ;
		Name = "lblLastPasswordUsed"


	ADD OBJECT cmdshowdetails AS commandbutton WITH ;
		Top = 195, ;
		Left = 488, ;
		Height = 23, ;
		Width = 84, ;
		Caption = "Show Details", ;
		ZOrderSet = 17, ;
		Name = "cmdShowDetails"


	ADD OBJECT lblcounter AS label WITH ;
		FontName = "Consolas", ;
		FontSize = 12, ;
		Caption = "1234567890123456789012345678901234567890", ;
		Left = 121, ;
		Top = 149, ;
		ForeColor = RGB(128,128,128), ;
		ZOrderSet = 18, ;
		Name = "lblCounter"


	ADD OBJECT cmdsave AS commandbutton WITH ;
		Top = 151, ;
		Left = 488, ;
		Height = 41, ;
		Width = 84, ;
		Picture = "..\..\bmps\save1.bmp", ;
		Caption = "Save", ;
		PicturePosition = 1, ;
		PictureSpacing = 1, ;
		ZOrderSet = 19, ;
		Name = "cmdSave"



	PROCEDURE Load
		Dodefault()

		thisform.OldLibraries			= Set("Library")
		set library to (m._encryptdll) additive
		thisform.PasswordGenerator		= Newobject('RandomPasswordGenerator', 'x:\foxv\classes\PasswordGenerator.prg')
	ENDPROC


	PROCEDURE Destroy
		local lcOldLibraries

		lcOldLibraries			= thisform.OldLibraries
		set library to &lcOldLibraries
	ENDPROC


	PROCEDURE txtcurrentpassword.Refresh
		if not Isnull(thisform.CurrentPasswordPK)
			if Indexseek(thisform.CurrentPasswordPK, .t., 'Passwords', 'PK')
				this.Value				= Decrypt(Alltrim(Passwords.Password), Evaluate(_ITKEY), 1024)
			endif
		endif
	ENDPROC


	PROCEDURE txtnewpassword.GotFocus
		textbox::gotFocus()
	ENDPROC


	PROCEDURE txtnewpassword.InteractiveChange
		Dodefault()
		thisform.Refresh()
	ENDPROC


	PROCEDURE cmdgenerate.Click
		thisform.txtNewPassword.Value			= thisform.PasswordGenerator.newPassword()
		thisform.Refresh()
	ENDPROC




	PROCEDURE commandbutton1.Click
		_cliptext				= Alltrim(thisform.txtCurrentPassword.Value)
	ENDPROC


	PROCEDURE txtlastpasswordused.Refresh
		if not Isnull(thisform.LastPasswordPK)
			if Indexseek(thisform.LastPasswordPK, .t., 'Passwords', 'PK')
				this.Value				= Decrypt(Alltrim(Passwords.Password), Evaluate(_ITKEY), 1024)
			endif
		endif
	ENDPROC


	PROCEDURE commandbutton2.Click
		_cliptext				= Alltrim(thisform.txtLastPasswordUsed.Value)
	ENDPROC


	PROCEDURE cmdshowdetails.Click
		local llPasswordOK, lcPassword, lcError, lcPreviousPassword

		lcError				= ''
		lcPassword			= Alltrim(thisform.txtNewPassword.Value)
		lcPreviousPassword	= Alltrim(thisform.txtLastPasswordUsed.Value)
		llPasswordOK		= thisform.PasswordGenerator.CheckPassword(lcPassword, lcPreviousPassword, @lcError)
		if llPasswordOK
			Messagebox('The password seems to be OK')
		else
			Messagebox(lcError, 16, 'Invalid password: ' + lcPassword)
		endif
	ENDPROC


	PROCEDURE cmdsave.Click
		insert into Passwords ;
				( ;
					CreatedOn, ;
					CreatedBy, ;
					Password ;
				) ;
			values ;
				( ;
					Datetime(), ;
					_TempID, ;
					Encrypt(Alltrim(thisform.txtNewPassword.Value), Evaluate(_ITKEY), 1024) ;
				)

		thisform.ctrUnusedPasswords.lstUnusedPasswords.Requery()
		thisform.ctrUnusedPasswords.lstUnusedPasswords.Refresh()
	ENDPROC



ENDDEFINE

DEFINE CLASS ctrCheckListClass as Container
	ADD OBJECT chkvalidlength AS checkbox WITH ;
		Top = 3, ;
		Left = 3, ;
		Height = 34, ;
		Width = 359, ;
		FontName = "Tahoma", ;
		WordWrap = .T., ;
		AutoSize = .F., ;
		Alignment = 0, ;
		Caption = "The password must be at least 12 characters long but no more than 40 characters long", ;
		Enabled = .F., ;
		DisabledForeColor = RGB(0,128,0), ;
		Name = "chkValidLength"


	ADD OBJECT chkminimuncharacters AS checkbox WITH ;
		Top = 38, ;
		Left = 3, ;
		Height = 56, ;
		Width = 359, ;
		FontName = "Tahoma", ;
		WordWrap = .T., ;
		AutoSize = .F., ;
		Alignment = 0, ;
		Caption = "The password must contain at least one lower-case alphabetic character, one upper-case alphabetic character and two numeric characters", ;
		Enabled = .F., ;
		DisabledForeColor = RGB(0,128,0), ;
		Name = "chkMinimunCharacters"


	ADD OBJECT checkbox3 AS checkbox WITH ;
		Top = 90, ;
		Left = 3, ;
		Height = 45, ;
		Width = 359, ;
		FontName = "Tahoma", ;
		WordWrap = .T., ;
		AutoSize = .F., ;
		Alignment = 0, ;
		Caption = "The password must contain only a combination of the following characters: 'a' to 'z', 'A' to 'Z' and '0' to '9'", ;
		Enabled = .F., ;
		DisabledForeColor = RGB(0,128,0), ;
		Name = "checkbox3"


	ADD OBJECT checkbox4 AS checkbox WITH ;
		Top = 134, ;
		Left = 3, ;
		Height = 46, ;
		Width = 359, ;
		FontName = "Tahoma", ;
		WordWrap = .T., ;
		AutoSize = .F., ;
		Alignment = 0, ;
		Caption = "The first eight characters of the password must contain at least one numeric character and two alpabetic characters", ;
		Enabled = .F., ;
		DisabledForeColor = RGB(0,128,0), ;
		Name = "checkbox4"


	ADD OBJECT checkbox5 AS checkbox WITH ;
		Top = 187, ;
		Left = 3, ;
		Height = 58, ;
		Width = 359, ;
		FontName = "Tahoma", ;
		WordWrap = .T., ;
		AutoSize = .F., ;
		Alignment = 0, ;
		Caption = "The new password must differ from the previous password and cannot be a reverse or circular shift of the previous password. For this comparison, uppercase and lowercase letters are considered to be equal", ;
		Enabled = .F., ;
		DisabledForeColor = RGB(128,128,128), ;
		Name = "checkbox5"


	ADD OBJECT checkbox6 AS checkbox WITH ;
		Top = 252, ;
		Left = 3, ;
		Height = 53, ;
		Width = 359, ;
		FontName = "Tahoma", ;
		WordWrap = .T., ;
		AutoSize = .F., ;
		Alignment = 0, ;
		Caption = "The new password must have at least three characters that are different from the old password. For this comparison, uppercase and lowercase letters  are considered to be equal", ;
		Enabled = .F., ;
		DisabledForeColor = RGB(0,128,0), ;
		Name = "checkbox6"

	PROCEDURE chkvalidlength.Refresh
		this.Value				= thisform.PasswordGenerator.CheckLength(thisform.txtNewPassword.Value)
		this.DisabledForeColor	= Iif(this.Value, Rgb(0, 128, 0), Rgb(128, 0, 0))
	ENDPROC


	PROCEDURE chkminimuncharacters.Refresh
		local lcPassword

		lcPassword				= thisform.txtNewPassword.Value
		with thisform.PasswordGenerator
			this.Value				= .CheckEnoughLowerCaseLetters(lcPassword) and .CheckEnoughUpperCaseLetters(lcPassword) and .CheckEnoughDigits(lcPassword)
		endwith
		this.DisabledForeColor	= Iif(this.Value, Rgb(0, 128, 0), Rgb(128, 0, 0))
	ENDPROC


	PROCEDURE checkbox3.Refresh
		local lcPassword

		lcPassword				= thisform.txtNewPassword.Value
		with thisform.PasswordGenerator
			this.Value				= .CheckValididyOfChars(lcPassword)
		endwith
		this.DisabledForeColor	= Iif(this.Value, Rgb(0, 128, 0), Rgb(128, 0, 0))
	ENDPROC


	PROCEDURE checkbox4.Refresh
		local lcRootPassword

		lcRootPassword			= Left(thisform.txtNewPassword.Value, 8)
		with thisform.PasswordGenerator
			this.Value				= .CheckEnoughStartingDigits(lcRootPassword) and .CheckEnoughStartingLetters(lcRootPassword)
		endwith
		this.DisabledForeColor	= Iif(this.Value, Rgb(0, 128, 0), Rgb(128, 0, 0))
	ENDPROC


	PROCEDURE checkbox6.Refresh
		with thisform.PasswordGenerator
			this.Value				= .CheckDifferentCharactersCount(thisform.txtNewPassword.Value, thisform.txtCurrentPassword.Value) > 3
		endwith

		this.DisabledForeColor	= Iif(this.Value, Rgb(0, 128, 0), Rgb(128, 0, 0))
	ENDPROC

enddefine
Password Manager, rule 7 is missing...
* Rules are:
*		The FTPS server performs the following validations on the password before accepting it:
*	1	· The password must be ASCII character encoded text.
*	2	· The password must be at least 12 characters long but no more than 40 characters long.
*	3	· The password must contain at least one lower-case alphabetic character, one uppercase
*		alphabetic character, and two numeric characters.
*	4	· The password must contain only a combination of the following characters: ‘a’ to ‘z’,
*		‘A’ to ‘Z’, and ‘0’ to ‘9’.
*	5	· The first eight characters of the password must contain at least one numeric character
*		and two alphabetic characters.
*	6	· The password cannot be a circular shift of the user id (note that such a password
*		would be invalid anyway because it would be only nine characters long and therefore
*		too short).
*	7	· The new password must differ from the previous password and cannot be a reverse or
*		circular shift of the previous password. For this comparison, uppercase letters and
*		lowercase letters are considered to be equal.
*	8	· The new password must have at least three characters that are different from the old
*		password. For this comparison, uppercase letters and lowercase letters are considered
*		to be equal.k

#define MAX_LENGTH			40				&& Rule 2
#define	MIN_LENGTH			12				&& Rule 2
#define MIN_LOWERCASE		1				&& Rule 3
#define MIN_UPPERCASE		1				&& Rule 3
#define MIN_DIGITS			2				&& Rule 3
#define ROOT_LENGTH			8				&& Rule 5
#define ROOT_ALPHACOUNT		2				&& Rule 5
#define ROOT_DIGITSCOUNT	2				&& Rule 5
#define ALL_DIGITS			'0123456789'
#define ALL_LETTERS			'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
#define MIN_DIFFCHARCOUNT	3

* Commented code is for testing purposes only

*!*	local lnLength

*!*	loRPG				= Createobject('RandomPasswordGenerator')
*!*	clear
*!*	*? 'Len' + Chr(9) + 'Digits' + Chr(9) + 'Lower' + Chr(9) + 'Upper' + Chr(9) + 'Root N' + Chr(9) + 'Root Char' + Chr(13)+Chr(10)

*!*	for i =1 to 25
*!*		lcPassword			= loRPG.newPassword()
*!*		lcError				= ''
*!*		llPasswordOK		= loRPG.CheckPassword(lcPassword, @lcError)
*!*		if llPasswordOK
*!*			? lcPassword, 'OK'
*!*		else
*!*			Messagebox(lcError, 16, 'Invalid password: ' + lcPassword)
*!*		endif
*!*	next i

*!*	lcError				= ''
*!*	lcPassword			= Inputbox('Enter the password')
*!*	llPasswordOK		= loRPG.CheckPassword(lcPassword, @lcError)
*!*	if llPasswordOK
*!*		? lcPassword, 'OK'
*!*	else
*!*		Messagebox(lcError, 16, 'Invalid password: ' + lcPassword)
*!*	endif


*!*	return



define class RandomPasswordGenerator as Session
	protected Random as Object
	
	function Init() as Boolean
		this.Random				= Newobject('RandomFunctions')
		return .t.
	endfunc
	
	procedure Destroy() as VOID
		this.Random				= null
		return null
	endproc
	
	function newPassword() as String
		local lnLength, lnLowerCaseCount, lnUpperCaseCount, lnDigitsCount, lnRootNumCount, lnRootCharCount
		local lcPassword, lcRoot
		
		lnLength			= this.Random.getRandomInteger(MIN_LENGTH, MAX_LENGTH)
		lnDigitsCount		= this.Random.getRandomInteger(MIN_DIGITS, lnLength - MIN_UPPERCASE - MIN_LOWERCASE)
		lnLowerCaseCount	= this.Random.getRandomInteger(MIN_LOWERCASE, lnLength - lnDigitsCount - MIN_UPPERCASE)
		lnUpperCaseCount	= lnLength - lnDigitsCount - lnLowerCaseCount
		lnRootNumCount		= this.Random.getRandomInteger(ROOT_DIGITSCOUNT, Min(lnDigitsCount, ROOT_LENGTH - ROOT_DIGITSCOUNT))
		lnRootCharCount		= ROOT_LENGTH - lnRootNumCount
		
		* Get the first 8 Characters, first the digits then the chars, later this will be shuffled
		lcUnshuffledRoot	= ''

		* Getting the digits
		for lnPosition = 1 to lnRootNumCount
			lcUnshuffledRoot	= lcUnshuffledRoot + this.Random.getRandomDigit()
		next lnPosition

		* Getting the chars, we need to keep a count on how many UpperCase and LowerCase chars are used
		for lnPosition = 1 to lnRootCharCount
			do case
				case lnUpperCaseCount > 0 and lnLowerCaseCount > 0
					lcChar				= this.Random.getRandomLetter()
				case lnUpperCaseCount > 0
					lcChar				= this.Random.getRandomUpperCase()
				case lnLowerCaseCount > 0
					lcChar				= this.Random.getRandomLowerCase()
				otherwise
					**** OOOOPSSS. Take a deep breath and think about this.
			endcase

			lcUnshuffledRoot	= lcUnshuffledRoot + lcChar
			if Isupper(lcChar)
				lnUpperCaseCount	= lnUpperCaseCount - 1
			else
				lnLowerCaseCount	= lnLowerCaseCount - 1
			endif
		next lnPosition

		lcRoot				= this.Random.StringShuffle(lcUnshuffledRoot)
		lnDigitsCount		= lnDigitsCount - lnRootNumCount
		lcPassword			= ''
		for lnPosition = 1 to lnDigitsCount
			lcPassword			= lcPassword + this.Random.getRandomDigit()
		next lnPosition

		for lnPosition = 1 to lnUpperCaseCount
			lcPassword			= lcPassword + this.Random.getRandomUpperCase()
		next lnPosition
		
		for lnPosition = 1 to lnLowerCaseCount
			lcPassword			= lcPassword + this.Random.getRandomLowerCase()
		next lnPosition

		return lcRoot + this.Random.StringShuffle(lcPassword)
	endfunc

	function CheckLength(tcPassword as String) as Boolean
		return Between(Len(tcPassword), MIN_LENGTH, MAX_LENGTH)
	endfunc

	function CheckValididyOfChars(tcPassword as String) as Boolean
		local lcInvalidCharacters

		lcInvalidCharacters	= Chrtran(Upper(tcPassword), ALL_DIGITS + ALL_LETTERS, '')
		return Len(lcInvalidCharacters) = 0
	endfunc
	
	function CheckEnoughStartingDigits(tcPasswordRoot as String) as Boolean
		local lnDigitsRoot

		lnDigitsRoot		= Len(tcPasswordRoot) - Len(Chrtran(tcPasswordRoot, ALL_DIGITS, ''))
		return lnDigitsRoot >= ROOT_DIGITSCOUNT
	endfunc

	function CheckEnoughStartingLetters(tcPasswordRoot as String) as Boolean
		local lnLettersRoot

		lnLettersRoot		= Len(tcPasswordRoot) - Len(Chrtran(tcPasswordRoot, ALL_DIGITS, ''))
		return lnLettersRoot >= ROOT_ALPHACOUNT
	endfunc
	
	function CheckEnoughDigits(tcPassword as String) as Boolean
		local lnDigits

		lnDigits			= Len(tcPassword) - Len(Chrtran(tcPassword, ALL_DIGITS, ''))
		return lnDigits >= MIN_DIGITS
	endfunc
	
	function CheckEnoughLowerCaseLetters(tcPassword as String) as Boolean
		local lnTotalLowerCase
		
		lnTotalLowerCase	= Len(tcPassword) - Len(Chrtran(tcPassword, Lower(ALL_LETTERS), ''))
		return lnTotalLowerCase >= MIN_LOWERCASE
	endfunc
	
	function CheckEnoughUpperCaseLetters(tcPassword as String) as Boolean
		local lnTotalUpperCase
		
		lnTotalUpperCase	= Len(tcPassword) - Len(Chrtran(tcPassword, ALL_LETTERS, ''))
		return lnTotalUpperCase >= MIN_UPPERCASE
	endfunc

	function CheckDifferentCharactersCount(tcCurrentPassword as String, tcPreviousPassword as String) as Integer
		return Len(Chrtran(Upper(tcCurrentPassword), Upper(tcPreviousPassword), ''))
	endfunc

	function CheckPassword(tcPassword as String, tcPreviousPassword, tcResult as String) as Boolean
		local lcRoot, lcResult, llSetResult, lcInvalidCharacters, lcPreviousPassword, lcNewCharacters

		llSetResult			= Pcount() = 3
		lcResult			= ''		
		lcPreviousPassword	= Iif(Vartype(tcPreviousPassword) = 'C', tcPreviousPassword, '')
		
		* Check the length
		if not Between(Len(tcPassword), MIN_LENGTH, MAX_LENGTH)
			lcResult			= 'Invalid Length. Current value: ' + Transform(Len(tcPassword))
		endif

		lcInvalidCharacters	= Chrtran(tcPassword, ALL_DIGITS + ALL_LETTERS + Lower(ALL_LETTERS), '')
		if Len(lcInvalidCharacters) # 0
			lcResult			= lcResult + Iif(Empty(lcResult), '', Chr(13)) + 'The password has invalid characters: [' + lcInvalidCharacters + ']'
		endif

		lcRoot				= Left(tcPassword, ROOT_LENGTH)
		lnDigitsRoot		= Len(lcRoot) - Len(Chrtran(lcRoot, ALL_DIGITS, ''))
		lnUpperCRoot		= Len(lcRoot) - Len(Chrtran(lcRoot, ALL_LETTERS, '')) - lnDigitsRoot
		lnLowerCRoot		= Len(lcRoot) - lnDigitsRoot - lnUpperCRoot
		
		* At least two MIN_DIGITS digits at the beginning
		if lnDigitsRoot < MIN_DIGITS
			lcResult			= lcResult + Iif(Empty(lcResult), '', Chr(13)) + 'Insuficient digits at start: ' + Transform(lnDigitsRoot)
		endif
		
		* At least two ROOT_ALPHACOUNT chars within the firt ROOT_ALPHACOUNT characters
		if lnUpperCRoot + lnLowerCRoot < ROOT_ALPHACOUNT
			lcResult			= lcResult + Iif(Empty(lcResult), '', Chr(13)) + 'Insuficient letters at start: ' + Transform(lnUpperCRoot + lnLowerCRoot)
		endif

		* At Lest MIN_LOWERCASE lower case char
		lnTotalLowerCase	= Len(tcPassword) - Len(Chrtran(tcPassword, Lower(ALL_LETTERS), ''))
		if lnTotalLowerCase < MIN_LOWERCASE
			lcResult			= lcResult + Iif(Empty(lcResult), '', Chr(13)) + 'Insuficient lower case letters: ' + Transform(lnTotalLowerCase)
		endif

		* At Lest MIN_UPPERCASE lower case char
		lnTotalUpperCase	= Len(tcPassword) - Len(Chrtran(tcPassword, ALL_LETTERS, ''))
		if lnTotalUpperCase < MIN_UPPERCASE
			lcResult			= lcResult + Iif(Empty(lcResult), '', Chr(13)) + 'Insuficient upper case letters: ' + Transform(lnTotalUpperCase)
		endif

		* Check how many characters are different
		lcNewCharacters		= Chrtran(Upper(tcPassword), Upper(lcPreviousPassword), '')
		if Len(lcNewCharacters) < MIN_DIFFCHARCOUNT
			lcResult			= lcResult + Iif(Empty(lcResult), '', Chr(13)) + 'Insuficient new characters.' + Chr(13) + Chr(9) + 'Try using some from this group: [' + Chrtran(ALL_DIGITS + ALL_LETTERS + Lower(ALL_LETTERS), lcPreviousPassword, '') + ']'
		endif

		if llSetResult
			tcResult		= lcResult
		endif
		return Empty(lcResult)
	endfunc
enddefine
Random generator class:
*******************************************************************************************************************
*                                                                                                                 *
* Collection of functions to return random numbers or letters                                                     *
*                                                                                                                 *
* Methods:                                                                                                        *
*                                                                                                                 *
* ReSeed               - Set a new seed for the internal random number generator                                  *
* getRandomDigit       - Returns a random digit as character ('0'..'9')                                           *
* getRandomLowerCase   - Returns a random lower case letter  ('a'..'z')                                           *
* getRandomUpperCase   - Returns a random upper case letter  ('A'..'Z')                                           *
* getRandomLetter      - Returns a random upper or lower case letter ('A'..'Z'|'a'..'z')                          *
*                                                                                                                 *
*                                                                                                                 *
*******************************************************************************************************************

define class RandomFunctions as Session
	function init() as Boolean
		Rand(-1)
		return .t.
	endfunc

	procedure ReSeed(tnNewSeed as Number) as VOID
		Rand(Iif(Vartype(tnNewSeed) = 'N', tnNewSeed, -1))
		return null
	endproc
	
	function getRandomDigit() as Character
		return this.getRandomAscii(Asc('0'), Asc('9'))
	endfunc

	function getRandomLowerCase() as Character
		return this.getRandomAscii(Asc('a'), Asc('z'))
	endfunc

	function getRandomUpperCase() as Character
		return this.getRandomAscii(Asc('A'), Asc('Z'))
	endfunc

	function getRandomLetter() as Character
		return Iif(Rand() < 0.5, this.getRandomUpperCase(), this.getRandomLowerCase())
	endfunc

	function getRandomNumber() as Number
		return Rand()
	endfunc

	function getRandomInteger(tnLowerLimit as Integer, tnUpperLimit as Integer) as Integer
		local lnLowerLimit, lnUpperLimit, lnAux
		
		lnLowerLimit			= Iif(Vartype(tnLowerLimit) # 'N' or Vartype(tnUpperLimit) # 'N', 0, Int(tnLowerLimit))
		lnUpperLimit			= Iif(Vartype(tnUpperLimit) # 'N', Iif(Vartype(tnLowerLimit) # 'N', 1, Int(tnLowerLimit)), Int(tnUpperLimit))
		if lnUpperLimit < lnLowerLimit
			lnAux					= lnLowerLimit
			lnLowerLimit			= lnUpperLimit
			lnUpperLimit			= lnAux
		endif
		
		* Default will be getRandomInteger(0, 1)
		* getRandom(5) = getRandomInteger(0, 5)
		
		return Int(Rand() * (lnUpperLimit - lnLowerLimit + 1)) + lnLowerLimit
	endfunc

	function getRandomAscii(tnLowerLimit as Integer, tnUpperLimit as Integer) as Character
		local lnLowerLimit, lnUpperLimit
		
		* Default will be getRandomAscii(0, 255)
		lnLowerLimit			= Iif(Vartype(tnLowerLimit) # 'N' or Vartype(tnUpperLimit) # 'N', 0, Int(tnLowerLimit))
		lnUpperLimit			= Iif(Vartype(tnUpperLimit) # 'N', Iif(Vartype(tnLowerLimit) # 'N', 255, Int(tnLowerLimit)), Int(tnUpperLimit))
		return Chr(this.getRandomInteger(lnLowerLimit, lnUpperLimit))
	endfunc

	* http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
	function StringShuffle(tcUnshuffled as String) as String
		local lnChars, lnChar, lcShuffled, lnPosition, lnRandomChar, lcTempChar
		
		lnChars				= Len(tcUnshuffled)
		lcShuffled			= tcUnshuffled

		for lnChar = lnChars to 1 step -1
			lnPosition			= this.getRandomInteger(1, lnChar)
			lcRandomChar		= Substr(lcShuffled, lnPosition, 1)
			lcTempChar			= Substr(lcShuffled, lnChar, 1)
			lcShuffled			= Stuff(lcShuffled, lnChar, 1, lcRandomChar)
			lcShuffled			= Stuff(lcShuffled, lnPosition, 1, lcTempChar)
		next lnChar
		
		return lcShuffled
	endfunc	
enddefine
Hopefully this mess can help you, let me know if something is missing other than the things I mentioned.

Hugo
"The five senses obstruct or deform the apprehension of reality."
Jorge L. Borges?

"Premature optimization is the root of all evil in programming."
Donald Knuth, repeating C. A. R. Hoare

"To die for a religion is easier than to live it absolutely"
Jorge L. Borges
Précédent
Suivant
Répondre
Fil
Voir

Click here to load this message in the networking platform